diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..6950f44 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index dc2d3b3..4fefe03 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,5 @@ out/ src/main/resources/firebase/ #/src/main/java/com/campick/server/common/config/DataInitializer.java + +*/.DS_Store \ No newline at end of file diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000..d01d7dd Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/main/.DS_Store b/src/main/.DS_Store new file mode 100644 index 0000000..4394bb9 Binary files /dev/null and b/src/main/.DS_Store differ diff --git a/src/main/java/com/campick/server/api/chat/controller/ChatImageController.java b/src/main/java/com/campick/server/api/chat/controller/ChatImageController.java new file mode 100644 index 0000000..2931f13 --- /dev/null +++ b/src/main/java/com/campick/server/api/chat/controller/ChatImageController.java @@ -0,0 +1,29 @@ +package com.campick.server.api.chat.controller; + +import com.campick.server.api.chat.dto.ChatImageReqDto; +import com.campick.server.api.chat.dto.ChatImageResDto; +import com.campick.server.api.product.service.ChatImageService; +import com.campick.server.common.response.ApiResponse; +import com.campick.server.common.response.SuccessStatus; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Map; + +@RestController +@RequestMapping("/api/chat/image") +@RequiredArgsConstructor +public class ChatImageController { + private final ChatImageService chatImageService; + + @PostMapping(consumes = {"multipart/form-data"}) + public ResponseEntity> upload(@RequestPart("chatId") Long chatId, + @RequestPart("file") MultipartFile file) { + String imageUrl = chatImageService.uploadImage(chatId, file); + ChatImageResDto chatImageResDto = ChatImageResDto.builder() + .chatImageUrl(imageUrl).build(); + return ApiResponse.success(SuccessStatus.UPLOAD_CHAT_IMAGE_SUCCESS, chatImageResDto); + } +} diff --git a/src/main/java/com/campick/server/api/chat/dto/ChatImageReqDto.java b/src/main/java/com/campick/server/api/chat/dto/ChatImageReqDto.java new file mode 100644 index 0000000..7dabdcc --- /dev/null +++ b/src/main/java/com/campick/server/api/chat/dto/ChatImageReqDto.java @@ -0,0 +1,12 @@ +package com.campick.server.api.chat.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class ChatImageReqDto { + private Long chatId; +} diff --git a/src/main/java/com/campick/server/api/chat/dto/ChatImageResDto.java b/src/main/java/com/campick/server/api/chat/dto/ChatImageResDto.java new file mode 100644 index 0000000..7c90de7 --- /dev/null +++ b/src/main/java/com/campick/server/api/chat/dto/ChatImageResDto.java @@ -0,0 +1,13 @@ +package com.campick.server.api.chat.dto; + +import com.campick.server.api.product.dto.ProductImageResDto; +import lombok.*; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ChatImageResDto { + private String chatImageUrl; +} \ No newline at end of file diff --git a/src/main/java/com/campick/server/api/chat/entity/ChatImage.java b/src/main/java/com/campick/server/api/chat/entity/ChatImage.java new file mode 100644 index 0000000..429a4f3 --- /dev/null +++ b/src/main/java/com/campick/server/api/chat/entity/ChatImage.java @@ -0,0 +1,23 @@ +package com.campick.server.api.chat.entity; + +import jakarta.persistence.*; +import lombok.*; + +@Entity +@Table(name = "chat_image") +@Getter @Setter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +@Builder +public class ChatImage { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "chat_id", nullable = false) + private ChatRoom chatRoom; + + @Column(name = "image_url", nullable = false) + private String imageUrl; +} diff --git a/src/main/java/com/campick/server/api/chat/repository/ChatImageRepository.java b/src/main/java/com/campick/server/api/chat/repository/ChatImageRepository.java new file mode 100644 index 0000000..eb3e007 --- /dev/null +++ b/src/main/java/com/campick/server/api/chat/repository/ChatImageRepository.java @@ -0,0 +1,7 @@ +package com.campick.server.api.chat.repository; + +import com.campick.server.api.chat.entity.ChatImage; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ChatImageRepository extends JpaRepository { +} diff --git a/src/main/java/com/campick/server/api/product/service/ChatImageService.java b/src/main/java/com/campick/server/api/product/service/ChatImageService.java new file mode 100644 index 0000000..c6acf46 --- /dev/null +++ b/src/main/java/com/campick/server/api/product/service/ChatImageService.java @@ -0,0 +1,22 @@ +package com.campick.server.api.product.service; + +import com.campick.server.api.chat.repository.ChatImageRepository; +import com.campick.server.common.storage.FirebaseStorageService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Map; + +@Service +@RequiredArgsConstructor +public class ChatImageService { + private final ChatImageRepository chatImageRepository; + private final FirebaseStorageService firebaseStorageService; + + @Transactional + public String uploadImage(Long chatId, MultipartFile file) { + return firebaseStorageService.uploadChatImage(chatId, file); + } +} diff --git a/src/main/java/com/campick/server/common/response/SuccessStatus.java b/src/main/java/com/campick/server/common/response/SuccessStatus.java index 0776859..a0ceacc 100644 --- a/src/main/java/com/campick/server/common/response/SuccessStatus.java +++ b/src/main/java/com/campick/server/common/response/SuccessStatus.java @@ -68,6 +68,7 @@ public enum SuccessStatus { SEND_MY_CHATROOMS(HttpStatus.OK, "내 채팅방 조회 성공"), SEND_TOTAL_UNREAD_MSG(HttpStatus.OK, "총 안 읽은 메시지 수 조회 성공"), COMPLETE_CHAT(HttpStatus.OK, "채팅방 종료 완료"), + UPLOAD_CHAT_IMAGE_SUCCESS(HttpStatus.OK, "채팅방 내 이미지 업로드 성공"), /** diff --git a/src/main/java/com/campick/server/common/storage/FirebaseStorageService.java b/src/main/java/com/campick/server/common/storage/FirebaseStorageService.java index 568a68c..1b2079f 100644 --- a/src/main/java/com/campick/server/common/storage/FirebaseStorageService.java +++ b/src/main/java/com/campick/server/common/storage/FirebaseStorageService.java @@ -84,6 +84,22 @@ public Map uploadProductImage(MultipartFile file) { } } + public String uploadChatImage(Long chatId, MultipartFile file) { + if (file == null || file.isEmpty()) + throw new BadRequestException(ErrorStatus.EMPTY_FILE_EXCEPTION.getMessage()); + + try { + String ext = extractExtension(file.getOriginalFilename()); + String objectName = String.format("chat/%d%s", chatId, ext); + + StorageClient.getInstance().bucket().create(objectName, file.getBytes(), file.getContentType()); + + return String.format("%s/o/%s?alt=media",storageBaseUrl, urlEncode(objectName)); + } catch (IOException e) { + throw new ImageUploadFailedException(ErrorStatus.IMAGE_UPLOAD_FAILED_EXCEPTION); + } + } + private void uploadThumbnail(MultipartFile file, String objectName, int width, int height) throws IOException { ByteArrayOutputStream thumbnailOStream = new ByteArrayOutputStream(); diff --git a/src/main/resources/.DS_Store b/src/main/resources/.DS_Store new file mode 100644 index 0000000..336c522 Binary files /dev/null and b/src/main/resources/.DS_Store differ