-
Notifications
You must be signed in to change notification settings - Fork 2
[#174][FEATURE] 프로필 이미지 등록 기능 추가 #176
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
Open
sleepyhoon
wants to merge
25
commits into
dev
Choose a base branch
from
feat/member-profile-image
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
46ffd35
Feat: image 사이즈 정의
sleepyhoon 6154b5e
Refactor: extractExtension 유틸 메서드로 분리
sleepyhoon c1b3fd8
Refactor: @Value 어노테이션 대신 @ConfigurationProperties 사용
sleepyhoon b891d4b
Feat: 이미지 공통 필드를 담는 ImageFile 구현
sleepyhoon c31d155
Feat: 이미지 상태 enum 추가
sleepyhoon b2d13a1
Refactor: 디렉토리 이동
sleepyhoon d488ade
Feat: 채팅 이미지 엔티티 구현
sleepyhoon 9e121f4
Feat: 유저 프로필 엔티티 구현
sleepyhoon 30bdc32
Fix: 반환값에 이미지 id 추가
sleepyhoon 76a078e
Fix: 서비스 로직 수정
sleepyhoon 3891ea4
Test: Test 수정
sleepyhoon 8790f85
Fix: 원본 이미지는 origin 경로에 저장되도록 수정
sleepyhoon 419e4f6
Feat: index 적용
sleepyhoon 24b6493
Docs: 주석 추가
sleepyhoon 14e679e
Docs: 문서화 보강
sleepyhoon 90c92c4
Fix: 업로드 시 presigned url 사용하지 않고 File 직접 업로드로 변경
sleepyhoon cc32e41
Fix: 사진 업로드 반영한 추상화 완료
sleepyhoon 64a3da2
Fix: 프로필 사진 업로드 로직 완성
sleepyhoon 12fe24c
Fix: 프로필 수정 로직 변경
sleepyhoon 5b04a29
Fix: objectKey 반환 시 domain + bucket 이름 추가 로직 구현
sleepyhoon 4d775dc
Test: Test 수정
sleepyhoon 0722fb5
Docs: 문서화 내용 수정
sleepyhoon b37518b
Docs: 주석 보강
sleepyhoon f8615bf
Fix: copilot PR 반영
sleepyhoon 643f05f
Fix: 문서 수정
sleepyhoon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,69 +1,68 @@ | ||
| = 👥 file API | ||
| = 📁 File API | ||
| :doctype: book | ||
| :icons: font | ||
| :source-highlighter: highlightjs | ||
| :toc: left | ||
| :toclevels: 3 | ||
| :sectlinks: | ||
|
|
||
| == 👥 그룹 관련 응답 코드 (I01) | ||
| [[overview]] | ||
| == 개요: 이미지 파일 업로드 | ||
|
|
||
| StudyPals는 `multipart/form-data` 형식을 사용하여 이미지 파일을 서버로 직접 업로드합니다. 전체적인 프로세스는 다음과 같습니다. | ||
|
|
||
| . *파일 전송*: 클라이언트는 `multipart/form-data` 요청을 통해 이미지 파일과 필요한 메타데이터(채팅방 ID 등)를 서버로 전송합니다. | ||
| . *서버 처리*: 서버는 수신한 파일을 검증하고, 스토리지(MinIO)에 업로드합니다. | ||
| . *데이터 저장*: 업로드가 성공하면 파일의 메타데이터(경로, 원본 이름 등)를 데이터베이스에 저장합니다. | ||
| . *응답 반환*: 저장된 이미지의 식별자(ID)와 접근 가능한 URL을 클라이언트에 반환합니다. | ||
|
|
||
| [[response-codes]] | ||
| == 📄 파일 관련 응답 코드 (F01) | ||
|
|
||
| |=== | ||
| | 기능 코드 | 설명 | ||
|
|
||
| | 00 | 프로필 이미지 업로드 Presigned URL 조회 | ||
| | 01 | 채팅 이미지 업로드 Presigned URL 조회 | ||
| | `FILE_IMAGE_UPLOAD` | 이미지 파일 업로드 성공 | ||
| |=== | ||
|
|
||
| == ✨ API 문서 | ||
|
|
||
| === 파일 API | ||
| === 1. 프로필 이미지 업로드 | ||
| '''' | ||
|
|
||
| ==== 1. 프로필 이미지 업로드 URL 조회 | ||
|
|
||
| *Description* + | ||
|
|
||
| ''' | ||
|
|
||
| 프로필 이미지 업로드를 위한 Presigned URL을 조회합니다. 해당 Presigned URL을 통해 MinIO에 직접 요청하여 이미지를 업로드해야 합니다. | ||
| 사용자의 프로필 이미지를 업로드합니다. 기존 프로필 이미지가 존재할 경우, 새로운 이미지로 교체됩니다. | ||
|
|
||
| - *HTTP Method*: `POST` | ||
| - *Endpoint*: `/files/image/profile` | ||
| - *Content-Type*: `multipart/form-data` | ||
|
|
||
| *REQUEST* + | ||
|
|
||
| ''' | ||
|
|
||
| include::{snippets}/image-file-controller-rest-docs-test/get-profile-upload-url_success/http-request.adoc[] | ||
| include::{snippets}/image-file-controller-rest-docs-test/get-profile-upload-url_success/request-fields.adoc[] | ||
| include::{snippets}/image-file-controller-rest-docs-test/get-profile-upload-url_success/request-parts.adoc[] | ||
|
|
||
| *RESPONSE* + | ||
|
|
||
| ''' | ||
|
|
||
| include::{snippets}/image-file-controller-rest-docs-test/get-profile-upload-url_success/response-fields.adoc[] | ||
| include::{snippets}/image-file-controller-rest-docs-test/get-profile-upload-url_success/http-response.adoc[] | ||
|
|
||
| '''' | ||
|
|
||
| ==== 2. 채팅 이미지 업로드 URL 조회 | ||
|
|
||
| === 2. 채팅 이미지 업로드 | ||
| '''' | ||
| *Description* + | ||
|
|
||
| ''' | ||
|
|
||
| 채팅 이미지 업로드를 위한 Presigned URL을 조회합니다. 해당 Presigned URL을 통해 MinIO에 직접 요청하여 이미지를 업로드해야 합니다. | ||
| 채팅방에서 사용할 이미지를 업로드합니다. | ||
|
|
||
| - *HTTP Method*: `POST` | ||
| - *Endpoint*: `/files/image/chat` | ||
| - *Content-Type*: `multipart/form-data` | ||
| - *Requires Authentication*: Yes | ||
|
|
||
| *REQUEST* + | ||
|
|
||
| ''' | ||
|
|
||
| include::{snippets}/image-file-controller-rest-docs-test/get-chat-upload-url_success/http-request.adoc[] | ||
| include::{snippets}/image-file-controller-rest-docs-test/get-chat-upload-url_success/request-fields.adoc[] | ||
| include::{snippets}/image-file-controller-rest-docs-test/get-chat-upload-url_success/query-parameters.adoc[] | ||
| include::{snippets}/image-file-controller-rest-docs-test/get-chat-upload-url_success/request-parts.adoc[] | ||
|
|
||
| *RESPONSE* + | ||
|
|
||
| ''' | ||
|
|
||
| include::{snippets}/image-file-controller-rest-docs-test/get-chat-upload-url_success/response-fields.adoc[] | ||
| include::{snippets}/image-file-controller-rest-docs-test/get-chat-upload-url_success/http-response.adoc[] |
7 changes: 7 additions & 0 deletions
7
src/main/java/com/studypals/domain/chatManage/dao/ChatImageRepository.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package com.studypals.domain.chatManage.dao; | ||
|
|
||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
|
|
||
| import com.studypals.domain.chatManage.entity.ChatImage; | ||
|
|
||
| public interface ChatImageRepository extends JpaRepository<ChatImage, Long> {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
src/main/java/com/studypals/domain/chatManage/entity/ChatImage.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package com.studypals.domain.chatManage.entity; | ||
|
|
||
| import jakarta.persistence.Entity; | ||
| import jakarta.persistence.FetchType; | ||
| import jakarta.persistence.Index; | ||
| import jakarta.persistence.JoinColumn; | ||
| import jakarta.persistence.ManyToOne; | ||
| import jakarta.persistence.Table; | ||
|
|
||
| import lombok.AccessLevel; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
| import lombok.experimental.SuperBuilder; | ||
|
|
||
| import com.studypals.global.file.entity.ImageFile; | ||
|
|
||
| /** | ||
| * 채팅방(ChatRoom) 내에서 전송된 이미지의 메타데이터를 관리하는 엔티티입니다. | ||
| * <p> | ||
| * 이 엔티티는 {@link ImageFile}을 상속받아 이미지 파일의 공통 속성을 관리하며, | ||
| * {@link ChatRoom}과 다대일(Many-to-One) 관계를 맺습니다. | ||
| * 채팅 이미지는 한 번 생성되면 수정되지 않는 불변(Immutable)의 특성을 가집니다. | ||
| * | ||
| * <p><b>주요 특징:</b> | ||
| * <ul> | ||
| * <li><b>상속 관계:</b> {@link ImageFile}의 모든 속성을 상속받습니다.</li> | ||
| * <li><b>연관 관계:</b> 여러 개의 채팅 이미지가 하나의 {@link ChatRoom}에 속합니다.</li> | ||
| * <li><b>불변성:</b> 생성 후 상태가 변경되지 않습니다. (수정 기능 없음)</li> | ||
| * <li><b>인덱싱:</b> 이미지 처리 상태({@code imageStatus})와 생성일({@code createdAt})에 복합 인덱스가 설정되어 있어, | ||
| * 리사이징 등 비동기 처리 대상 조회 시 성능을 향상시킵니다.</li> | ||
| * </ul> | ||
| * | ||
| * @author sleepyhoon | ||
| * @since 2026-01-15 | ||
| * @see ImageFile | ||
| * @see ChatRoom | ||
| * @see com.studypals.domain.chatManage.worker.ChatImageManager | ||
| */ | ||
| @Entity | ||
| @Getter | ||
| @SuperBuilder | ||
| @NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
| @Table( | ||
| name = "chat_image", | ||
| indexes = @Index(name = "idx_chat_image_status_created_at", columnList = "imageStatus, createdAt")) | ||
| public class ChatImage extends ImageFile { | ||
|
|
||
| @ManyToOne(fetch = FetchType.LAZY) | ||
| @JoinColumn(name = "chat_room_id", nullable = false) | ||
| private ChatRoom chatRoom; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
src/main/java/com/studypals/domain/chatManage/worker/ChatImageWriter.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| package com.studypals.domain.chatManage.worker; | ||
|
|
||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| import lombok.RequiredArgsConstructor; | ||
|
|
||
| import com.studypals.domain.chatManage.dao.ChatImageRepository; | ||
| import com.studypals.domain.chatManage.entity.ChatImage; | ||
| import com.studypals.domain.chatManage.entity.ChatRoom; | ||
| import com.studypals.global.annotations.Worker; | ||
| import com.studypals.global.file.FileUtils; | ||
|
|
||
| /** | ||
| * 채팅 이미지의 메타데이터를 데이터베이스에 저장하는 역할을 전담하는 Worker 클래스입니다. | ||
| * <p> | ||
| * 이 클래스는 CQRS(Command Query Responsibility Segregation) 패턴의 'Command' 측면을 담당하며, | ||
| * 시스템의 상태를 변경하는 '쓰기(Write)' 작업에만 집중합니다. | ||
| * {@link Transactional} 어노테이션을 통해 데이터 저장 작업의 원자성을 보장합니다. | ||
| * | ||
| * @author sleepyhoon | ||
| * @since 2026-01-15 | ||
| * @see ChatImage | ||
| * @see ChatImageRepository | ||
| */ | ||
| @Worker | ||
| @RequiredArgsConstructor | ||
| public class ChatImageWriter { | ||
| private final ChatImageRepository chatImageRepository; | ||
|
|
||
| /** | ||
| * 채팅 이미지의 메타데이터를 생성하고 데이터베이스에 저장합니다. | ||
| * <p> | ||
| * 이 메서드는 클라이언트가 서버를 통해 이미지를 업로드할 때 호출되며, | ||
| * 서버가 파일을 처리하고 스토리지에 저장하는 흐름 속에서 해당 파일의 메타데이터를 데이터베이스에 기록합니다. | ||
| * | ||
| * @param chatRoom 이미지가 속한 채팅방 엔티티 | ||
| * @param objectKey 스토리지에 저장될 파일의 고유 객체 키 | ||
| * @param fileName 원본 파일의 이름 | ||
| * @return 데이터베이스에 저장된 {@link ChatImage}의 고유 ID | ||
| */ | ||
| @Transactional | ||
| public Long save(ChatRoom chatRoom, String objectKey, String fileName) { | ||
| String extension = FileUtils.extractExtension(fileName); | ||
|
|
||
| ChatImage savedImage = chatImageRepository.save(ChatImage.builder() | ||
| .chatRoom(chatRoom) | ||
| .objectKey(objectKey) | ||
| .originalFileName(fileName) | ||
| .mimeType(extension) | ||
| .build()); | ||
|
|
||
| return savedImage.getId(); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.