From 06c6434d14ddf1691ddbf5e26ba3b2e715f9b9d6 Mon Sep 17 00:00:00 2001 From: kkw610 Date: Thu, 28 May 2026 09:40:39 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20API=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20?= =?UTF-8?q?=EC=A7=88=EB=AC=B8/=EB=8C=93=EA=B8=80=20imageUrl=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../question/controller/ImageController.java | 67 +++++++++++++++++++ .../domain/question/dto/QuestionReqDTO.java | 2 + .../question/service/QuestionService.java | 2 + backend/src/main/resources/application.yml | 3 + 4 files changed, 74 insertions(+) create mode 100644 backend/src/main/java/com/example/Piroin/project/domain/question/controller/ImageController.java diff --git a/backend/src/main/java/com/example/Piroin/project/domain/question/controller/ImageController.java b/backend/src/main/java/com/example/Piroin/project/domain/question/controller/ImageController.java new file mode 100644 index 0000000..72fcbdc --- /dev/null +++ b/backend/src/main/java/com/example/Piroin/project/domain/question/controller/ImageController.java @@ -0,0 +1,67 @@ +package com.example.Piroin.project.domain.question.controller; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.UUID; + +/* 이미지 업로드/조회 컨트롤러 + +[흐름] +1. POST /api/images 로 이미지 파일 전송 → URL 반환 +2. 반환된 URL을 질문/댓글 등록 요청의 imageUrl 필드에 포함 +3. GET /api/images/{filename} 으로 저장된 이미지 조회 */ +@RestController +@RequestMapping("/api/images") +public class ImageController { + + @Value("${file.upload-dir}") + private String uploadDir; + + /* 이미지 업로드 + POST /api/images + Content-Type: multipart/form-data */ + @PostMapping + public ResponseEntity> uploadImage( + @RequestParam("file") MultipartFile file + ) throws IOException { + + // 저장 폴더 없으면 생성 + File dir = new File(uploadDir); + if (!dir.exists()) { + dir.mkdirs(); + } + + // 파일명 중복 방지: UUID + 원본 확장자 + String originalName = file.getOriginalFilename(); + String extension = originalName.substring(originalName.lastIndexOf(".")); + String savedName = UUID.randomUUID() + extension; + + // 파일 저장 + file.transferTo(new File(uploadDir + savedName)); + + return ResponseEntity.ok(Map.of("imageUrl", "/api/images/" + savedName)); + } + + // 이미지 조회 + // GET /api/images/{filename} + @GetMapping("/{filename}") + public ResponseEntity getImage(@PathVariable String filename) throws IOException { + File file = new File(uploadDir + filename); + + if (!file.exists()) { + return ResponseEntity.notFound().build(); + } + + String contentType = filename.endsWith(".png") ? "image/png" : "image/jpeg"; + + return ResponseEntity.ok() + .header("Content-Type", contentType) + .body(java.nio.file.Files.readAllBytes(file.toPath())); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/example/Piroin/project/domain/question/dto/QuestionReqDTO.java b/backend/src/main/java/com/example/Piroin/project/domain/question/dto/QuestionReqDTO.java index a902d6b..5cedbae 100644 --- a/backend/src/main/java/com/example/Piroin/project/domain/question/dto/QuestionReqDTO.java +++ b/backend/src/main/java/com/example/Piroin/project/domain/question/dto/QuestionReqDTO.java @@ -11,6 +11,7 @@ public class QuestionReqDTO { @NoArgsConstructor public static class CreateReq { private String content; + private String imageUrl; } // 질문 수정 요청 @@ -26,6 +27,7 @@ public static class UpdateReq { @NoArgsConstructor public static class CommentReq { private String content; + private String imageUrl; private Long parentCommentId; // 대댓글일 때만 값이 있음, 일반 댓글이면 null } diff --git a/backend/src/main/java/com/example/Piroin/project/domain/question/service/QuestionService.java b/backend/src/main/java/com/example/Piroin/project/domain/question/service/QuestionService.java index 5703f3b..07e65e9 100644 --- a/backend/src/main/java/com/example/Piroin/project/domain/question/service/QuestionService.java +++ b/backend/src/main/java/com/example/Piroin/project/domain/question/service/QuestionService.java @@ -133,6 +133,7 @@ public QuestionResDTO.CommentCreateRes createComment( .user(loginUser) .parentComment(parentComment) // 일반 댓글이면 null, 대댓글이면 부모 댓글 .content(request.getContent()) + .imageUrl(request.getImageUrl()) .createdAt(now) .updatedAt(now) .build(); @@ -224,6 +225,7 @@ public QuestionResDTO.CreateRes createQuestion(Long sessionId, QuestionReqDTO.Cr .session(session) .user(loginUser) .content(request.getContent()) + .imageUrl(request.getImageUrl()) .isResolved(false) .likeCount(0) .createdAt(LocalDateTime.now()) diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index cabf9f2..11c99f9 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -29,3 +29,6 @@ management: web: exposure: include: health + +file: + upload-dir: uploads/