Skip to content

Commit

Permalink
Merge pull request #14 from kjungw1025/feat/chatting
Browse files Browse the repository at this point in the history
feat: 채팅방 이미지 업로드, 다운로드 기능 추가 및 버그 수정
  • Loading branch information
kjungw1025 authored Feb 4, 2024
2 parents 63750e7 + d612bf1 commit 76c1dac
Show file tree
Hide file tree
Showing 26 changed files with 632 additions and 107 deletions.
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

0 comments on commit 76c1dac

Please sign in to comment.