diff --git a/src/main/java/com/leets/team2/xclone/domain/member/controller/MemberController.java b/src/main/java/com/leets/team2/xclone/domain/member/controller/MemberController.java index b8473a3..096232c 100644 --- a/src/main/java/com/leets/team2/xclone/domain/member/controller/MemberController.java +++ b/src/main/java/com/leets/team2/xclone/domain/member/controller/MemberController.java @@ -1,6 +1,7 @@ package com.leets.team2.xclone.domain.member.controller; import com.leets.team2.xclone.common.ApiData; +import com.leets.team2.xclone.domain.member.dto.MemberDTO; import com.leets.team2.xclone.domain.member.dto.requests.CheckTagDuplicationGetRequest; import com.leets.team2.xclone.domain.member.dto.requests.MemberFindGetRequest; import com.leets.team2.xclone.domain.member.dto.responses.CheckTagDuplicationGetResponse; @@ -10,6 +11,9 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; public interface MemberController { @@ -18,7 +22,10 @@ public interface MemberController { ResponseEntity> getCheckTagDuplication( CheckTagDuplicationGetRequest request); - @Operation(summary = "멤버 정보 가져오기 API", description = "Tag로 멤버 정보를 가져옵니다.") - @ApiResponse(responseCode = "200", description = "멤버 정보 가져오기 성공", content = @Content(schema = @Schema(implementation = MemberFindGetResponse.class))) - ResponseEntity> getMember(MemberFindGetRequest request); + @Operation(summary = "멤버 정보 가져오기 API", description = "Tag로 멤버 정보를 찾습니다.") + ResponseEntity> getMemberInfo(@RequestParam String tag); + + @Operation(summary = "프로필 사진 수정 API", description = "자신의 프로필 사진을 수정합니다.") + ResponseEntity> updateProfilePicture(@RequestPart(value="image",required = false) MultipartFile image); + } diff --git a/src/main/java/com/leets/team2/xclone/domain/member/controller/MemberControllerImpl.java b/src/main/java/com/leets/team2/xclone/domain/member/controller/MemberControllerImpl.java index 1fb873c..137c4ba 100644 --- a/src/main/java/com/leets/team2/xclone/domain/member/controller/MemberControllerImpl.java +++ b/src/main/java/com/leets/team2/xclone/domain/member/controller/MemberControllerImpl.java @@ -1,18 +1,20 @@ package com.leets.team2.xclone.domain.member.controller; import com.leets.team2.xclone.common.ApiData; +import com.leets.team2.xclone.common.auth.MemberContext; +import com.leets.team2.xclone.common.auth.annotations.UseGuards; +import com.leets.team2.xclone.common.auth.guards.MemberGuard; +import com.leets.team2.xclone.domain.member.dto.MemberDTO; import com.leets.team2.xclone.domain.member.dto.requests.CheckTagDuplicationGetRequest; -import com.leets.team2.xclone.domain.member.dto.requests.MemberFindGetRequest; import com.leets.team2.xclone.domain.member.dto.responses.CheckTagDuplicationGetResponse; -import com.leets.team2.xclone.domain.member.dto.responses.MemberFindGetResponse; +import com.leets.team2.xclone.domain.member.entities.Member; import com.leets.team2.xclone.domain.member.service.MemberService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; @Controller @RequestMapping("/api/members") @@ -31,11 +33,26 @@ public ResponseEntity> getCheckTagDuplic } @Override - @GetMapping - public ResponseEntity> getMember( - @ModelAttribute MemberFindGetRequest request) { - return ApiData.ok( - this.memberService.findMembersByTag(request.tag()) - ); + @GetMapping("") + public ResponseEntity> getMemberInfo(@RequestParam String tag) { + Member targetMember = memberService.findMemberByTag(tag); + MemberDTO.Response response = MemberDTO.Response.builder() + .birthDate(targetMember.getBirthDate()) + .tag(targetMember.getTag()) + .nickname(targetMember.getNickname()) + .introduction(targetMember.getIntroduction()) + .build(); + + return ApiData.ok(response); } + + @Override + @UseGuards({MemberGuard.class}) + @PatchMapping("/profile/picture") + public ResponseEntity> updateProfilePicture(@RequestPart(value="image",required = false) MultipartFile image){ + Member currentMember = MemberContext.getMember(); + MemberDTO.Response response = memberService.updateProfilePicture(currentMember, image); + return ApiData.ok(response); + } + } diff --git a/src/main/java/com/leets/team2/xclone/domain/member/dto/MemberDTO.java b/src/main/java/com/leets/team2/xclone/domain/member/dto/MemberDTO.java new file mode 100644 index 0000000..3cfcdc7 --- /dev/null +++ b/src/main/java/com/leets/team2/xclone/domain/member/dto/MemberDTO.java @@ -0,0 +1,16 @@ +package com.leets.team2.xclone.domain.member.dto; + +import lombok.Builder; + +import java.time.LocalDateTime; + +public class MemberDTO { + @Builder + public record Response( + LocalDateTime birthDate, + String tag, + String nickname, + String introduction, + String profilePicture + ){} +} \ No newline at end of file diff --git a/src/main/java/com/leets/team2/xclone/domain/member/entities/Member.java b/src/main/java/com/leets/team2/xclone/domain/member/entities/Member.java index ef2f495..926e8f3 100644 --- a/src/main/java/com/leets/team2/xclone/domain/member/entities/Member.java +++ b/src/main/java/com/leets/team2/xclone/domain/member/entities/Member.java @@ -1,10 +1,15 @@ package com.leets.team2.xclone.domain.member.entities; import com.leets.team2.xclone.common.entity.AbstractEntity; +import com.leets.team2.xclone.image.converter.ImageListConverter; import jakarta.persistence.Column; +import jakarta.persistence.Convert; import jakarta.persistence.Entity; import jakarta.persistence.Table; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -33,4 +38,16 @@ public class Member extends AbstractEntity { @Column(name = "kakao_id", nullable = false, unique = true) private Long kakaoId; + + @Column(name="image_url") + @Convert(converter = ImageListConverter.class) + private List imageUrl = new ArrayList<>(); + + public void setImage(String profileImageUrl) { + if (this.imageUrl == null) { + this.imageUrl = new ArrayList<>(); // Initialize if it's null + } + this.imageUrl.clear(); + this.imageUrl.add(profileImageUrl); + } } diff --git a/src/main/java/com/leets/team2/xclone/domain/member/service/MemberService.java b/src/main/java/com/leets/team2/xclone/domain/member/service/MemberService.java index 097cff5..3df2297 100644 --- a/src/main/java/com/leets/team2/xclone/domain/member/service/MemberService.java +++ b/src/main/java/com/leets/team2/xclone/domain/member/service/MemberService.java @@ -1,15 +1,20 @@ package com.leets.team2.xclone.domain.member.service; +import com.leets.team2.xclone.domain.member.dto.MemberDTO; import com.leets.team2.xclone.domain.member.dto.responses.MemberFindGetResponse; import com.leets.team2.xclone.domain.member.entities.Member; import com.leets.team2.xclone.domain.member.repository.MemberRepository; import com.leets.team2.xclone.exception.NoSuchMemberException; + import java.util.List; import java.util.Optional; + +import com.leets.team2.xclone.image.service.ImageSaveService; import lombok.RequiredArgsConstructor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; import java.util.NoSuchElementException; @@ -19,6 +24,7 @@ public class MemberService { private static final Log log = LogFactory.getLog(MemberService.class); private final MemberRepository memberRepository; + private final ImageSaveService imageSaveService; public boolean checkMemberExistsBy(String nickname, Long kakaoId) { return this.memberRepository.existsByNicknameAndKakaoId(nickname, kakaoId); @@ -56,4 +62,20 @@ public MemberFindGetResponse findMembersByTag(String tag) { this.memberRepository.findByTagContaining(tag).forEach(memberFindGetResponse::add); return memberFindGetResponse; } + + public MemberDTO.Response updateProfilePicture(Member currentMember, MultipartFile image) { + + if(!image.isEmpty()){ + List imageUrl = imageSaveService.uploadImages(List.of(image)); + currentMember.setImage(imageUrl.get(0)); + } + memberRepository.save(currentMember); + return MemberDTO.Response.builder() + .birthDate(currentMember.getBirthDate()) + .tag(currentMember.getTag()) + .nickname(currentMember.getNickname()) + .introduction(currentMember.getIntroduction()) + .profilePicture(currentMember.getImageUrl().get(0)) + .build(); + } } diff --git a/src/main/java/com/leets/team2/xclone/image/converter/ImageListConverter.java b/src/main/java/com/leets/team2/xclone/image/converter/ImageListConverter.java index ae62ed6..f762951 100644 --- a/src/main/java/com/leets/team2/xclone/image/converter/ImageListConverter.java +++ b/src/main/java/com/leets/team2/xclone/image/converter/ImageListConverter.java @@ -5,8 +5,8 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.persistence.AttributeConverter; - import java.io.IOException; +import java.util.ArrayList; import java.util.List; public class ImageListConverter implements AttributeConverter, String> { @@ -16,6 +16,9 @@ public class ImageListConverter implements AttributeConverter, Stri @Override public String convertToDatabaseColumn(List attribute) { + if (attribute == null || attribute.isEmpty()) { + return ""; + } try { return mapper.writeValueAsString(attribute); } catch (JsonProcessingException e) { @@ -25,6 +28,9 @@ public String convertToDatabaseColumn(List attribute) { @Override public List convertToEntityAttribute(String dbData) { + if (dbData == null || dbData.isEmpty()) { + return new ArrayList<>(); // Return an empty list if dbData is null or empty + } try { return mapper.readValue(dbData, new TypeReference<>() {}); } catch (IOException e) {