Skip to content
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

feat: 채팅방 이미지 업로드, 다운로드 기능 추가 및 버그 수정 #14

Merged
merged 11 commits into from
Feb 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.dku.council.domain.chat.controller;

import com.dku.council.domain.chat.model.FileType;
import com.dku.council.domain.chat.model.MessageType;
import com.dku.council.domain.chat.model.dto.Message;
import com.dku.council.domain.chat.model.dto.request.RequestChatDto;
Expand Down Expand Up @@ -87,14 +88,15 @@ public void enterUser(@Payload RequestChatDto chat,
LocalDateTime messageTime = LocalDateTime.now();

// 입장 메시지 저장
chatRoomMessageService.create(chat.getRoomId(), chat.getType().toString(), chat.getUserId(), chat.getSender(), enterMessage, messageTime);
chatRoomMessageService.create(chat.getRoomId(), chat.getType().toString(), chat.getUserId(), chat.getSender(), enterMessage, messageTime, "", "", chat.getFileType().toString());

Message message = Message.builder()
.type(chat.getType())
.roomId(chat.getRoomId())
.sender(chat.getSender())
.message(enterMessage)
.messageTime(messageTime)
.fileType(chat.getFileType())
.build();

sender.send(topic, message);
Expand All @@ -110,14 +112,17 @@ public void enterUser(@Payload RequestChatDto chat,
public void sendMessage(@Payload RequestChatDto chat) {
LocalDateTime messageTime = LocalDateTime.now();

chatRoomMessageService.create(chat.getRoomId(), chat.getType().toString(), chat.getUserId(), chat.getSender(), chat.getMessage(), messageTime);
chatRoomMessageService.create(chat.getRoomId(), chat.getType().toString(), chat.getUserId(), chat.getSender(), chat.getMessage(), messageTime, chat.getFileName(), chat.getFileUrl(), chat.getFileType().toString());

Message message = Message.builder()
.type(chat.getType())
.roomId(chat.getRoomId())
.sender(chat.getSender())
.message(chat.getMessage())
.messageTime(messageTime)
.fileName(chat.getFileName())
.fileUrl(chat.getFileUrl())
.fileType(chat.getFileType())
.build();

sender.send(topic, message);
Expand Down Expand Up @@ -182,7 +187,11 @@ public List<String> userList(String roomId) {
return chatService.getUserList(roomId);
}


/**
* 채팅방 별, 이전에 나눈 채팅 메시지 리스트 반환
*
* @param roomId 채팅방 id
*/
@GetMapping("/chat/message/list")
@UserAuth
@ResponseBody
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.dku.council.domain.chat.controller;

import com.dku.council.domain.chat.exception.InvalidChatRoomUserException;
import com.dku.council.domain.chat.model.dto.request.RequestChatFileDto;
import com.dku.council.domain.chat.service.ChatService;
import com.dku.council.global.auth.jwt.AppAuthentication;
import com.dku.council.global.auth.role.UserAuth;
import com.dku.council.infra.nhn.global.service.service.NHNAuthService;
import com.dku.council.infra.nhn.s3.model.ChatUploadedImage;
import com.dku.council.infra.nhn.s3.model.ImageRequest;
import com.dku.council.infra.nhn.s3.service.ChatImageUploadService;
import com.dku.council.infra.nhn.s3.service.ObjectDownloadService;
import com.dku.council.infra.nhn.s3.service.ObjectStorageService;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.parameters.P;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

@Tag(name = "채팅방 파일", description = "채팅방 파일/이미지 업로드 및 다운로드 관련 api")
@RestController
@RequestMapping("/chat")
@RequiredArgsConstructor
public class ChatFileController {

private final ChatService chatService;
private final ChatImageUploadService chatImageUploadService;
private final ObjectDownloadService objectDownloadService;

private final NHNAuthService nhnAuthService;
private final ObjectStorageService objectStorageService;

// @PostMapping("/file/upload")

/**
* 이미지 업로드 기능
*
* @param request roomId와 전송할 이미지 파일에 대한 dto
*/
@PostMapping(value = "/image/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@UserAuth
public List<ChatUploadedImage> uploadImage(AppAuthentication auth,
@Valid @ModelAttribute RequestChatFileDto request) {
// 채팅방에 현재 참여중인 유저가 아니면, 해당 채팅방에 이미지 업로드를 할 수 없게
if (chatService.alreadyInRoom(request.getRoomId(), auth.getUserId())) {
return chatImageUploadService.newContext().uploadChatImages(
ImageRequest.ofList(request.getFiles()),
request.getRoomId(),
auth.getUserId());
} else {
throw new InvalidChatRoomUserException();
}
}

@GetMapping("/download/{fileName}")
@UserAuth
public ResponseEntity<byte[]> download(AppAuthentication auth,
@PathVariable String fileName,
@RequestParam("roomId") String roomId,
@RequestParam("fileUrl") String fileUrl) {
if (chatService.alreadyInRoom(roomId, auth.getUserId())) {
return objectDownloadService.downloadObject(fileName, fileUrl);
} else {
throw new InvalidChatRoomUserException();
}
}

// TODO : 파일 삭제시, chatRoomMessage에도 삭제된게 반영 되어야함
// @DeleteMapping("/file/delete")
// public void deleteFile(@RequestParam("roomId") String roomId,
// @RequestParam("fileUrl") String fileUrl) {
// objectStorageService.deleteChatFileByDirectUrl(nhnAuthService.requestToken(), fileUrl);
// }

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.dku.council.domain.chat.controller;

import com.dku.council.domain.chat.model.dto.response.ResponseChatRoomDto;
import com.dku.council.domain.chat.service.ChatFileService;
import com.dku.council.domain.chat.service.ChatService;
import com.dku.council.domain.chatmessage.service.ChatRoomMessageService;
import com.dku.council.domain.user.model.dto.response.ResponseUserInfoForChattingDto;
Expand All @@ -10,7 +11,6 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
Expand All @@ -22,10 +22,11 @@
@RequiredArgsConstructor
@Slf4j
public class ChatRoomController {
private final ChatService chatService;

private final UserService userService;
private final ChatService chatService;
private final ChatRoomMessageService chatRoomMessageService;
private final ChatFileService chatFileService;

/**
* 채팅방 리스트 화면
Expand Down Expand Up @@ -109,10 +110,14 @@ public boolean confirmPwd(@PathVariable String roomId,
*
* @param roomId 채팅방 id
*/
@DeleteMapping("/delete/{roomId}")
@DeleteMapping
@UserAuth
public String delChatRoom(@PathVariable String roomId, AppAuthentication auth){
public String delChatRoom(@RequestParam String roomId, AppAuthentication auth){

// 해당 채팅방에 존재하는 파일들 삭제
chatFileService.deleteAllFilesInChatRoom(roomId);

// 해당 채팅방에 존재하는 채팅 메시지들 삭제
chatRoomMessageService.deleteChatRoomMessages(roomId);

// roomId(UUID 값) 기준으로 채팅방 삭제
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.dku.council.domain.chat.exception;

import com.dku.council.global.error.exception.LocalizedMessageException;
import org.springframework.http.HttpStatus;

public class InvalidChatRoomUserException extends LocalizedMessageException {
public InvalidChatRoomUserException() { super(HttpStatus.BAD_REQUEST, "notfound.chat-room-user"); }
}
18 changes: 18 additions & 0 deletions src/main/java/com/dku/council/domain/chat/model/FileType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.dku.council.domain.chat.model;

public enum FileType {
/**
* 이미지
*/
IMAGE,

/**
* 파일
*/
FILE,

/**
* 일반 메시지 형태일 경우
*/
NONE
}
15 changes: 14 additions & 1 deletion src/main/java/com/dku/council/domain/chat/model/dto/Message.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.dku.council.domain.chat.model.dto;

import com.dku.council.domain.chat.model.FileType;
import com.dku.council.domain.chat.model.MessageType;
import lombok.Builder;
import lombok.Getter;
Expand Down Expand Up @@ -28,16 +29,28 @@ public class Message {
@NotNull
private LocalDateTime messageTime;

private String fileName;

private String fileUrl;

private FileType fileType;

@Builder
private Message(MessageType type,
String roomId,
String sender,
String message,
LocalDateTime messageTime) {
LocalDateTime messageTime,
String fileName,
String fileUrl,
FileType fileType) {
this.type = type;
this.roomId = roomId;
this.sender = sender;
this.message = message;
this.messageTime = messageTime;
this.fileName = fileName;
this.fileUrl = fileUrl;
this.fileType = fileType;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.dku.council.domain.chat.model.dto.request;

import com.dku.council.domain.chat.model.FileType;
import com.dku.council.domain.chat.model.MessageType;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
Expand All @@ -18,10 +19,7 @@ public class RequestChatDto {

private final String message;

// private String time;
//
// /* 파일 업로드 관련 변수 (일단 보류) */
// private String s3DataUrl; // 파일 업로드 url
// private String fileName; // 파일이름
// private String fileDir; // s3 파일 경로
private final String fileName; // 파일이름
private final String fileUrl; // s3에 업로드 된 위치
private final FileType fileType; // 이미지인지 파일인지
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.dku.council.domain.chat.model.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Getter
public class RequestChatFileDto {

@NotBlank
@Schema(description = "채팅방 번호", example = "d118101z-c737-4253-9911-ea2579405f42")
private final String roomId;

@Schema(description = "첨부 파일 목록")
private final List<MultipartFile> files;

public RequestChatFileDto(String roomId, List<MultipartFile> files) {
this.roomId = roomId;
this.files = Objects.requireNonNullElseGet(files, ArrayList::new);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.dku.council.domain.chat.service;

import com.dku.council.domain.chatmessage.model.entity.ChatRoomMessage;
import com.dku.council.domain.chatmessage.repository.ChatRoomMessageRepository;
import com.dku.council.infra.nhn.global.service.service.NHNAuthService;
import com.dku.council.infra.nhn.s3.service.ObjectStorageService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
@Slf4j
public class ChatFileService {

private final NHNAuthService nhnAuthService;
private final ObjectStorageService objectStorageService;

private final ChatRoomMessageRepository chatRoomMessageRepository;

public void deleteAllFilesInChatRoom(String roomId) {
List<ChatRoomMessage> imageMessageList = chatRoomMessageRepository.findAllByRoomIdAndFileType(roomId, "IMAGE");
List<ChatRoomMessage> fileMessageList = chatRoomMessageRepository.findAllByRoomIdAndFileType(roomId, "FILE");

if (!imageMessageList.isEmpty()) {
for (ChatRoomMessage chatRoomMessage : imageMessageList) {
objectStorageService.deleteChatFileByDirectUrl(nhnAuthService.requestToken(), chatRoomMessage.getFileUrl());
}
}

if (!fileMessageList.isEmpty()) {
for (ChatRoomMessage chatRoomMessage : fileMessageList) {
objectStorageService.deleteChatFileByDirectUrl(nhnAuthService.requestToken(), chatRoomMessage.getFileUrl());
}
}
}
}
19 changes: 8 additions & 11 deletions src/main/java/com/dku/council/domain/chat/service/ChatService.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,6 @@ public ResponseChatRoomDto createChatRoom(String roomName, String roomPwd, boole
.build();
chatRoomRepository.save(chatRoom);

ChatRoomUser chatRoomUser = ChatRoomUser.builder()
.chatRoom(chatRoom)
.user(user)
.build();
chatRoomUserRepository.save(chatRoomUser);

return new ResponseChatRoomDto(chatRoom.getRoomId(),
chatRoom.getRoomName(),
chatRoom.getUserCount(),
Expand Down Expand Up @@ -153,6 +147,14 @@ public String addUser(String roomId, String userName){
return user.getNickname();
}

/**
* 특정 채팅방에 참여중인 유저인지 확인
*/
public boolean alreadyInRoom(String roomId, Long userId) {
long chatRoomId = chatRoomRepository.findChatRoomByRoomId(roomId).orElseThrow(ChatRoomNotFoundException::new).getId();
return chatRoomUserRepository.existsUserByRoomIdAndUserId(chatRoomId, userId).isPresent();
}

/**
* 채팅방 유저 리스트 삭제
*/
Expand Down Expand Up @@ -204,9 +206,4 @@ public void delChatRoom(Long userId, String roomId, boolean isAdmin) {
}
log.info("삭제 완료 roomId : {}", roomId);
}

public boolean alreadyInRoom(String roomId, Long userId) {
long chatRoomId = chatRoomRepository.findChatRoomByRoomId(roomId).orElseThrow(ChatRoomNotFoundException::new).getId();
return chatRoomUserRepository.existsUserByRoomIdAndUserId(chatRoomId, userId).isPresent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,13 @@ public void setCreatedAt(LocalDateTime createdAt) {

@DynamoDBAttribute
private String content;

@DynamoDBAttribute
private String fileName;

@DynamoDBAttribute
private String fileUrl;

@DynamoDBAttribute
private String fileType;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ public interface ChatRoomMessageRepository extends CrudRepository<ChatRoomMessag
List<ChatRoomMessage> findAllByRoomIdOrderByCreatedAtAsc(String roomId);

void deleteAllByRoomId(String roomId);

List<ChatRoomMessage> findAllByRoomIdAndFileType(String roomId, String fileType);
}
Loading
Loading