diff --git a/backend/build.gradle b/backend/build.gradle index f597c38..7948525 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -46,8 +46,8 @@ dependencies { implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' // Lombok - compileOnly 'org.projectlombok:lombok' - annotationProcessor 'org.projectlombok:lombok' + compileOnly 'org.projectlombok:lombok:1.18.30' + annotationProcessor 'org.projectlombok:lombok:1.18.30' //WebSocket implementation 'org.springframework.boot:spring-boot-starter-websocket' diff --git a/backend/src/main/java/com/metlab_project/backend/controller/chatroom/ChatRoomController.java b/backend/src/main/java/com/metlab_project/backend/controller/chatroom/ChatRoomController.java index ccba282..d3c7a51 100644 --- a/backend/src/main/java/com/metlab_project/backend/controller/chatroom/ChatRoomController.java +++ b/backend/src/main/java/com/metlab_project/backend/controller/chatroom/ChatRoomController.java @@ -1,46 +1,62 @@ package com.metlab_project.backend.controller.chatroom; import com.metlab_project.backend.domain.dto.chatroom.req.ChatroomCreateRequest; +import com.metlab_project.backend.domain.dto.chatroom.res.ChatRoomResponse; +import com.metlab_project.backend.domain.dto.chatroom.res.MemberResponse; +import com.metlab_project.backend.domain.entity.Message; +import com.metlab_project.backend.domain.entity.user.User; +import com.metlab_project.backend.domain.dto.chatroom.res.ChatRoomDetailResponse; +import com.metlab_project.backend.service.chatroom.ChatRoomService; + import io.swagger.v3.oas.annotations.Operation; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; + +import java.util.List; + import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor @RequestMapping("/api/chatroom") -public class ChatroomController { - @GetMapping("/list") - @Operation(summary = "STATUS가 WAITING인 채팅룸 불러오기", description = "STATUS가 WAITING인 채팅룸을 불러옵니다.") - public ResponseEntity getAllChatroom(){ - //Status Waiting인 채팅룸 불러오는건데, /list-my에서 넘겨줄 본인이 속한 채팅방 제외하고 불러오면됨. - return ResponseEntity.ok(true); - } +public class ChatRoomController { + + private final ChatRoomService chatRoomService; - @GetMapping("/list-my") - @Operation(summary = "유저가 참가중인 채팅룸 불러오기", description = "유저가 참가중인 채팅룸을 불러옵니다.") - public ResponseEntity getMyChatroom(){ - //본인이 속한 채팅룸(Status 상관없이 불러오면 됨) - return ResponseEntity.ok(true); + @GetMapping("/list") + @Operation(summary = "모든 채팅룸 불러오기", description = "모든 채팅룸을 불러옵니다.") + public ResponseEntity getAllChatroom() { + List allChatRooms = chatRoomService.getAllChatrooms(); + return ResponseEntity.ok(allChatRooms); } @GetMapping("/participants/{chatroomid}") @Operation(summary = "채팅룸 참여 유저 불러오기", description = "특정 채팅룸의 참여자 목록을 불러옵니다.") - public ResponseEntity getParticipants(@PathVariable("chatroomid") String chatroomId){ - return ResponseEntity.ok(true); + public ResponseEntity getParticipants(@PathVariable("chatroomid") Integer chatroomId) { + List members = chatRoomService.getChatRoomDetail(chatroomId).getMembers(); + return ResponseEntity.ok(members); + } + @PostMapping + @Operation(summary = "채팅룸 생성하기", description = "채팅룸을 생성합니다.") + public ResponseEntity createChatroom(@Valid @RequestBody ChatroomCreateRequest request) { + // @Valid 사용 시 유효성 검증 실패 시 MethodArgumentNotValidException 발생 가능 + ChatRoomResponse newChatRoom = chatRoomService.createChatroom(request); + return ResponseEntity.ok(newChatRoom); } - @GetMapping("/summary/{chatroomid}") - @Operation(summary = "채팅룸 요약 불러오기", description = "특정 채팅룸의 요약 정보를 불러옵니다.") - public ResponseEntity getChatroomSummary(@PathVariable("chatroomid") String chatroomId){ - return ResponseEntity.ok(true); + @DeleteMapping("/{chatroomId}") + @Operation(summary = "채팅룸 삭제하기", description = "특정 채팅룸을 삭제합니다.") + public ResponseEntity deleteChatroom(@PathVariable("chatroomId") Integer chatroomId) { + chatRoomService.deleteChatroom(chatroomId); + return ResponseEntity.noContent().build(); // 204 No Content } - @PostMapping - @Operation(summary = "채팅룸 생성하기", description = "채팅룸을 생성합니다.") - public ResponseEntity createChatroom(@Valid @RequestBody ChatroomCreateRequest request){ - return ResponseEntity.ok(true); + @GetMapping("/{chatroomId}/messages") + @Operation(summary = "채팅룸 내역 가져오기", description = "특정 채팅룸의 채팅 내역을 가져옵니다.") + public ResponseEntity> getChatMessages(@PathVariable("chatroomId") Integer chatroomId) { + List messages = chatRoomService.getChatMessages(chatroomId); + return ResponseEntity.ok(messages); } } diff --git a/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/req/ChatroomCreateRequest.java b/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/req/ChatroomCreateRequest.java index 9e36f62..fd84b0e 100644 --- a/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/req/ChatroomCreateRequest.java +++ b/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/req/ChatroomCreateRequest.java @@ -3,17 +3,14 @@ import java.time.LocalDateTime; import lombok.AllArgsConstructor; import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; +import lombok.Getter; -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor +@Getter public class ChatroomCreateRequest { // 채팅룸 생성 ResponseDTO private String chatroomName; private LocalDateTime deadline; private String hashtags; private Integer maxUser; + private String host; } \ No newline at end of file diff --git a/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/res/ChatRoomDetailResponse.java b/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/res/ChatRoomDetailResponse.java new file mode 100644 index 0000000..2f54ad2 --- /dev/null +++ b/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/res/ChatRoomDetailResponse.java @@ -0,0 +1,21 @@ +package com.metlab_project.backend.domain.dto.chatroom.res; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +@Getter +@AllArgsConstructor +public class ChatRoomDetailResponse { + private Integer id; + private String name; + private String title; + private String subTitle; + private List members; + private Integer maxMembers; + private Boolean enterCheck; + private String host; + private Integer maleCount; + private Integer femaleCount; +} diff --git a/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/res/ChatRoomResponse.java b/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/res/ChatRoomResponse.java index dedb048..504121a 100644 --- a/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/res/ChatRoomResponse.java +++ b/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/res/ChatRoomResponse.java @@ -1,4 +1,34 @@ package com.metlab_project.backend.domain.dto.chatroom.res; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +@Getter +@AllArgsConstructor public class ChatRoomResponse { + private Integer id; + private String title; + private String subTitle; + private Integer maxMembers; + private Boolean enterCheck; + private String host; + private Integer maleCount; + private Integer femaleCount; + private String profileImage; + private Boolean hasStarted; + + public ChatRoomResponse(Integer id, String title, String subTitle, Integer maxMembers, Boolean enterCheck, String host, Integer maleCount, Integer femaleCount, String profileImage, Boolean hasStarted) { + this.id = id; + this.title = title; + this.subTitle = subTitle; + this.maxMembers = maxMembers; + this.enterCheck = enterCheck; + this.host = host; + this.maleCount = maleCount; + this.femaleCount = femaleCount; + this.profileImage = profileImage; + this.hasStarted = hasStarted; + } } diff --git a/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/res/MemberResponse.java b/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/res/MemberResponse.java new file mode 100644 index 0000000..1cfddf3 --- /dev/null +++ b/backend/src/main/java/com/metlab_project/backend/domain/dto/chatroom/res/MemberResponse.java @@ -0,0 +1,14 @@ +package com.metlab_project.backend.domain.dto.chatroom.res; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class MemberResponse { + private String gender; + private String major; + private String studentId; + private String nickname; + private String profileImage; +} diff --git a/backend/src/main/java/com/metlab_project/backend/domain/dto/message/res/MessageResponse.java b/backend/src/main/java/com/metlab_project/backend/domain/dto/message/res/MessageResponse.java deleted file mode 100644 index 5d4a78d..0000000 --- a/backend/src/main/java/com/metlab_project/backend/domain/dto/message/res/MessageResponse.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.metlab_project.backend.domain.dto.message.res; - -public class MessageResponse { -} \ No newline at end of file diff --git a/backend/src/main/java/com/metlab_project/backend/domain/entity/ChatRoom.java b/backend/src/main/java/com/metlab_project/backend/domain/entity/ChatRoom.java index 65f03e0..4a8f620 100644 --- a/backend/src/main/java/com/metlab_project/backend/domain/entity/ChatRoom.java +++ b/backend/src/main/java/com/metlab_project/backend/domain/entity/ChatRoom.java @@ -25,6 +25,15 @@ public class ChatRoom { @Column(name = "chatroom_name", nullable = false, length = 30) private String chatroomName; + @Column(name = "title", length = 100) + private String title; + + @Column(name = "sub_title", length = 100) + private String subTitle; + + @Column(name = "profile_image", length = 255) + private String profileImage; + @Column(name = "host", nullable = false, length = 30) private String host; // host's schoolEmail @@ -39,20 +48,28 @@ public class ChatRoom { @Column(name = "total_participant") private Integer totalParticipant; + @Column(name = "max_members") + private Integer maxMembers; + + @Column(name = "enter_check") + private Boolean enterCheck; + private LocalDateTime deadline; + @Enumerated(EnumType.STRING) @Builder.Default - @Column(name = "status") + @Column(name = "status", length = 20) private Status status = Status.WAITING; @Column(length = 100) private String hashtags; + @Builder.Default @ManyToMany(mappedBy = "chatRooms") private List users = new ArrayList<>(); - @OneToMany(mappedBy = "chatRoom") - private List messages; + @OneToMany(mappedBy = "chatRoom", cascade = CascadeType.ALL, orphanRemoval = true) + private List messages = new ArrayList<>(); public enum Status { WAITING, @@ -68,4 +85,4 @@ public void removeUser(User user) { this.users.remove(user); user.getChatRooms().remove(this); } -} \ No newline at end of file +} diff --git a/backend/src/main/java/com/metlab_project/backend/domain/entity/Message.java b/backend/src/main/java/com/metlab_project/backend/domain/entity/Message.java index f59c4fd..4476379 100644 --- a/backend/src/main/java/com/metlab_project/backend/domain/entity/Message.java +++ b/backend/src/main/java/com/metlab_project/backend/domain/entity/Message.java @@ -47,7 +47,7 @@ public class Message { @JoinColumn(name = "chatroom_id", insertable = false, updatable = false) private ChatRoom chatRoom; - private enum MessageType { + public enum MessageType { CHAT, JOIN, LEAVE, diff --git a/backend/src/main/java/com/metlab_project/backend/domain/entity/user/User.java b/backend/src/main/java/com/metlab_project/backend/domain/entity/user/User.java index 2256a71..8fbfea0 100644 --- a/backend/src/main/java/com/metlab_project/backend/domain/entity/user/User.java +++ b/backend/src/main/java/com/metlab_project/backend/domain/entity/user/User.java @@ -71,6 +71,12 @@ public class User { ) private List chatRooms = new ArrayList<>(); + @Column(length = 30) + private String major; + + @Column(length = 255) + private String profileImage; + public void addChatRoom(ChatRoom chatRoom) { this.chatRooms.add(chatRoom); chatRoom.getUsers().add(this); diff --git a/backend/src/main/java/com/metlab_project/backend/exception/CustomErrorCode.java b/backend/src/main/java/com/metlab_project/backend/exception/CustomErrorCode.java index c645b9f..54cab42 100644 --- a/backend/src/main/java/com/metlab_project/backend/exception/CustomErrorCode.java +++ b/backend/src/main/java/com/metlab_project/backend/exception/CustomErrorCode.java @@ -23,7 +23,9 @@ public enum CustomErrorCode { TOKEN_CLAIMS_EMPTY(HttpStatus.UNAUTHORIZED, "401", "Token claims are empty"), REFRESH_TOKEN_NOT_FOUND(HttpStatus.NOT_FOUND, "404", "Refresh token not found"), REFRESH_TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, "401", "Refresh token has expired"), - TOKEN_BLACKLISTED(HttpStatus.UNAUTHORIZED, "401", "Token has been blacklisted"); + TOKEN_BLACKLISTED(HttpStatus.UNAUTHORIZED, "401", "Token has been blacklisted"), + //그 외 + UNKNOWN(HttpStatus.INTERNAL_SERVER_ERROR, "500", "Internal Server Error occurred"); @NonNull private final HttpStatus httpStatus; diff --git a/backend/src/main/java/com/metlab_project/backend/exception/CustomException.java b/backend/src/main/java/com/metlab_project/backend/exception/CustomException.java index b117718..b86ea58 100644 --- a/backend/src/main/java/com/metlab_project/backend/exception/CustomException.java +++ b/backend/src/main/java/com/metlab_project/backend/exception/CustomException.java @@ -27,4 +27,5 @@ public CustomException(Exception exception) { this.detail = exception.getMessage(); } } -} \ No newline at end of file +} + diff --git a/backend/src/main/java/com/metlab_project/backend/repository/chatroom/ChatRoomRepository.java b/backend/src/main/java/com/metlab_project/backend/repository/chatroom/ChatRoomRepository.java index d849d80..96a4257 100644 --- a/backend/src/main/java/com/metlab_project/backend/repository/chatroom/ChatRoomRepository.java +++ b/backend/src/main/java/com/metlab_project/backend/repository/chatroom/ChatRoomRepository.java @@ -1,9 +1,14 @@ package com.metlab_project.backend.repository.chatroom; import com.metlab_project.backend.domain.entity.ChatRoom; + +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface ChatRoomRepository extends JpaRepository { + List findByStatus(ChatRoom.Status status); + List findByIdIn(List ids); } diff --git a/backend/src/main/java/com/metlab_project/backend/repository/message/MessageRepository.java b/backend/src/main/java/com/metlab_project/backend/repository/message/MessageRepository.java index 7c9a599..f0ddac0 100644 --- a/backend/src/main/java/com/metlab_project/backend/repository/message/MessageRepository.java +++ b/backend/src/main/java/com/metlab_project/backend/repository/message/MessageRepository.java @@ -4,6 +4,9 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface MessageRepository extends JpaRepository { + List findByChatroomIdAndTypeOrderByCreatedAtAsc(Integer chatroomId, Message.MessageType type); } diff --git a/backend/src/main/java/com/metlab_project/backend/service/chatroom/ChatRoomService.java b/backend/src/main/java/com/metlab_project/backend/service/chatroom/ChatRoomService.java index a798af0..de0eb39 100644 --- a/backend/src/main/java/com/metlab_project/backend/service/chatroom/ChatRoomService.java +++ b/backend/src/main/java/com/metlab_project/backend/service/chatroom/ChatRoomService.java @@ -1,8 +1,139 @@ package com.metlab_project.backend.service.chatroom; + +import com.metlab_project.backend.domain.dto.chatroom.res.ChatRoomDetailResponse; +import com.metlab_project.backend.domain.dto.chatroom.res.ChatRoomResponse; +import com.metlab_project.backend.domain.dto.chatroom.req.ChatroomCreateRequest; +import com.metlab_project.backend.domain.dto.chatroom.res.MemberResponse; +import com.metlab_project.backend.domain.entity.ChatRoom; +import com.metlab_project.backend.domain.entity.Message; +import com.metlab_project.backend.domain.entity.user.User; +import com.metlab_project.backend.repository.chatroom.ChatRoomRepository; +import com.metlab_project.backend.repository.message.MessageRepository; + import lombok.RequiredArgsConstructor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; +import java.util.List; +import java.util.stream.Collectors; + @Service @RequiredArgsConstructor public class ChatRoomService { + + private final ChatRoomRepository chatRoomRepository; + private final MessageRepository messageRepository; + + public List getAllChatrooms() { + return chatRoomRepository.findAll().stream() + .map(chatRoom -> new ChatRoomResponse( + chatRoom.getId(), + chatRoom.getTitle(), + chatRoom.getSubTitle(), + chatRoom.getMaxMembers(), + chatRoom.getEnterCheck(), + chatRoom.getHost(), + chatRoom.getParticipantMaleCount(), + chatRoom.getParticipantFemaleCount(), + chatRoom.getProfileImage(), + chatRoom.getStatus() == ChatRoom.Status.ACTIVE + )) + .collect(Collectors.toList()); + } + + public List getMyChatrooms() { + Integer currentUserId = getCurrentUserId(); + List myChatRooms = chatRoomRepository.findAll().stream() + .filter(chatRoom -> chatRoom.getUsers().stream() + .anyMatch(user -> user.getId().equals(currentUserId))) + .collect(Collectors.toList()); + + return myChatRooms.stream() + .map(chatRoom -> new ChatRoomResponse( + chatRoom.getId(), + chatRoom.getTitle(), + chatRoom.getSubTitle(), + chatRoom.getMaxMembers(), + chatRoom.getEnterCheck(), + chatRoom.getHost(), + chatRoom.getParticipantMaleCount(), + chatRoom.getParticipantFemaleCount(), + chatRoom.getProfileImage(), + chatRoom.getStatus() == ChatRoom.Status.ACTIVE + )) + .collect(Collectors.toList()); + } + + + public ChatRoomDetailResponse getChatRoomDetail(Integer roomId) { + ChatRoom chatRoom = chatRoomRepository.findById(roomId) + .orElseThrow(() -> new RuntimeException("채팅룸을 찾을 수 없습니다.")); + + List members = chatRoom.getUsers().stream() + .map(user -> new MemberResponse( + user.getGender(), + user.getMajor(), + user.getStudentId(), + user.getNickname(), + user.getProfileImage())) + .collect(Collectors.toList()); + + long maleCount = members.stream().filter(member -> "Male".equalsIgnoreCase(member.getGender())).count(); + long femaleCount = members.stream().filter(member -> "Female".equalsIgnoreCase(member.getGender())).count(); + + return new ChatRoomDetailResponse( + chatRoom.getId(), + chatRoom.getChatroomName(), + chatRoom.getTitle(), + chatRoom.getSubTitle(), + members, + chatRoom.getMaxMembers(), + chatRoom.getEnterCheck(), + chatRoom.getHost(), + (int) maleCount, + (int) femaleCount + ); + } + + public ChatRoomResponse createChatroom(ChatroomCreateRequest request) { + ChatRoom chatRoom = ChatRoom.builder() + .chatroomName(request.getTitle()) + .title(request.getTitle()) + .subTitle(request.getSubTitle()) + .profileImage(request.getProfileImage()) + .maxMembers(request.getMembersCount()) + .enterCheck(false) + .host(request.getHost()) + .status(ChatRoom.Status.WAITING) + .build(); + chatRoomRepository.save(chatRoom); + + return new ChatRoomResponse( + chatRoom.getId(), + chatRoom.getTitle(), + chatRoom.getSubTitle(), + chatRoom.getMaxMembers(), + chatRoom.getEnterCheck(), + chatRoom.getHost(), + chatRoom.getParticipantMaleCount(), + chatRoom.getParticipantFemaleCount(), + chatRoom.getProfileImage(), + chatRoom.getStatus() == ChatRoom.Status.ACTIVE + ); + } + + public void deleteChatroom(Integer chatroomId) { + chatRoomRepository.deleteById(chatroomId); + } + + public List getChatMessages(Integer chatroomId) { + return messageRepository.findByChatroomIdAndTypeOrderByCreatedAtAsc(chatroomId, Message.MessageType.CHAT); + } + + private Integer getCurrentUserId() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + User user = (User) authentication.getPrincipal(); + return user.getId(); + } }