Merge pull request #96 from TeamBNBN/be/ws

[Back-End] 웹소켓 채팅 및 퀴즈시작 추가
This commit is contained in:
김기창 2024-07-24 10:24:41 +09:00 committed by GitHub
commit a943b15c04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 339 additions and 17 deletions

View File

@ -19,6 +19,7 @@ import java.util.List;
*/ */
@RestController @RestController
@RequestMapping("/board") @RequestMapping("/board")
@CrossOrigin("*")
public class BoardController { public class BoardController {
private final JWTUtil jwtUtil; private final JWTUtil jwtUtil;
@ -30,22 +31,18 @@ public class BoardController {
} }
@GetMapping() @GetMapping()
public ResponseEntity<?> searchBoards( public ResponseEntity<List<ResponseBoardSummaryDto>> searchBoards(
@RequestParam(value = "category", required = false, defaultValue = "announcement") String category, @RequestParam(value = "category", required = false, defaultValue = "announcement") String category,
@RequestParam(value = "lectureId", required = true) long lectureId, @RequestParam(value = "lectureId") long lectureId,
@RequestParam(value = "pageNo", required = false, defaultValue = "0") int pageNo @RequestParam(value = "pageNo", required = false, defaultValue = "0") int pageNo
){ ){
List<ResponseBoardSummaryDto> boardSummaries = boardService.findBoards(pageNo, category, lectureId); List<ResponseBoardSummaryDto> boardSummaries = boardService.findBoards(pageNo, category, lectureId);
if(boardSummaries.isEmpty()){
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(boardSummaries, HttpStatus.OK); return new ResponseEntity<>(boardSummaries, HttpStatus.OK);
} }
@GetMapping(value = "/{boardId}") @GetMapping(value = "/{boardId}")
public ResponseEntity<?> getBoardDetail( public ResponseEntity<ResponseBoardDetailDto> getBoardDetail(
@PathVariable int boardId @PathVariable int boardId
){ ){
ResponseBoardDetailDto responseBoardDetailDto = boardService.findBoardDetail(boardId); ResponseBoardDetailDto responseBoardDetailDto = boardService.findBoardDetail(boardId);
@ -87,7 +84,7 @@ public class BoardController {
} }
@GetMapping(value = "/comment/{boardId}") @GetMapping(value = "/comment/{boardId}")
public ResponseEntity<?> getComments( public ResponseEntity<List<ResponseCommentDto>> getComments(
@PathVariable int boardId @PathVariable int boardId
){ ){
List<ResponseCommentDto> comments = boardService.findComments(boardId); List<ResponseCommentDto> comments = boardService.findComments(boardId);
@ -127,4 +124,10 @@ public class BoardController {
return new ResponseEntity<>(HttpStatus.OK); return new ResponseEntity<>(HttpStatus.OK);
} }
@ExceptionHandler()
public ResponseEntity<?> NoContentException(Exception exception){
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
} }

View File

@ -16,6 +16,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@ -49,14 +50,14 @@ public class BoardServiceImpl implements BoardService {
@Transactional @Transactional
public ResponseBoardDetailDto findBoardDetail(long boardId) { public ResponseBoardDetailDto findBoardDetail(long boardId) {
return boardRepository.findById(boardId) return boardRepository.findById(boardId)
.orElseThrow() .orElseThrow(NoSuchElementException::new)
.makeDetailDto(); .makeDetailDto();
} }
@Transactional @Transactional
public void createBoard(long userId, RequestBoardDto requestBoardDto) { public void createBoard(long userId, RequestBoardDto requestBoardDto) {
User user = userRepository.findById(userId).orElseThrow(); User user = userRepository.getReferenceById(userId);
Lecture lecture = lectureRepository.findById(requestBoardDto.getLectureId()).get(); Lecture lecture = lectureRepository.getReferenceById(requestBoardDto.getLectureId());
Board board = Board.builder() Board board = Board.builder()
.title(requestBoardDto.getTitle()) .title(requestBoardDto.getTitle())
@ -71,7 +72,7 @@ public class BoardServiceImpl implements BoardService {
@Transactional @Transactional
public void updateBoard(long boardId, RequestBoardUpdateDto requestBoardUpdateDto) { public void updateBoard(long boardId, RequestBoardUpdateDto requestBoardUpdateDto) {
Board board = boardRepository.findById(boardId).get(); Board board = boardRepository.findById(boardId).orElseThrow(IllegalArgumentException::new);
board.setTitle(requestBoardUpdateDto.getTitle()); board.setTitle(requestBoardUpdateDto.getTitle());
board.setContent(requestBoardUpdateDto.getContent()); board.setContent(requestBoardUpdateDto.getContent());
@ -82,7 +83,7 @@ public class BoardServiceImpl implements BoardService {
@Transactional @Transactional
public void deleteBoard(long boardId) { public void deleteBoard(long boardId) {
Board board = boardRepository.findById(boardId).get(); Board board = boardRepository.getReferenceById(boardId);
boardRepository.delete(board); boardRepository.delete(board);
} }
@ -96,8 +97,8 @@ public class BoardServiceImpl implements BoardService {
@Transactional @Transactional
public void createComment(long userId, long boardId, RequestCommentDto requestCommentDto) { public void createComment(long userId, long boardId, RequestCommentDto requestCommentDto) {
User user = userRepository.findById(userId).get(); User user = userRepository.getReferenceById(userId);
Board board = boardRepository.findById(boardId).get(); Board board = boardRepository.getReferenceById(boardId);
Comment comment = Comment.builder() Comment comment = Comment.builder()
.content(requestCommentDto.getContent()) .content(requestCommentDto.getContent())
@ -112,7 +113,7 @@ public class BoardServiceImpl implements BoardService {
@Transactional @Transactional
public void updateComment(long commentId, RequestCommentDto requestCommentDto) { public void updateComment(long commentId, RequestCommentDto requestCommentDto) {
Comment comment = commentRepository.findById(commentId).get(); Comment comment = commentRepository.findById(commentId).orElseThrow(IllegalArgumentException::new);
comment.setContent(requestCommentDto.getContent()); comment.setContent(requestCommentDto.getContent());
@ -121,7 +122,7 @@ public class BoardServiceImpl implements BoardService {
@Transactional @Transactional
public void deleteComment(long commentId) { public void deleteComment(long commentId) {
Comment comment = commentRepository.findById(commentId).get(); Comment comment = commentRepository.getReferenceById(commentId);
commentRepository.delete(comment); commentRepository.delete(comment);
} }

View File

@ -16,4 +16,5 @@ public interface LectureRepository extends JpaRepository<Lecture, Long> {
List<Lecture> findLecturesByUserId(Long userId); List<Lecture> findLecturesByUserId(Long userId);
Lecture findByIdAndUserId(long id, long userId);
} }

View File

@ -0,0 +1,25 @@
package com.edufocus.edufocus.ws.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfigurer implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/sub");
registry.setApplicationDestinationPrefixes("/pub");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry
.addEndpoint("/ws")
.setAllowedOrigins("*");
}
}

View File

@ -0,0 +1,92 @@
package com.edufocus.edufocus.ws.controller;
import com.edufocus.edufocus.user.util.JWTUtil;
import com.edufocus.edufocus.ws.entity.dto.MessageDto;
import com.edufocus.edufocus.ws.entity.dto.QuizDto;
import com.edufocus.edufocus.ws.entity.dto.ChatUserDto;
import com.edufocus.edufocus.ws.service.ChatService;
import org.springframework.context.event.EventListener;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;
import java.util.List;
@RestController
public class ChatController {
private final SimpMessageSendingOperations simpMessageSendingOperations;
private final ChatService chatService;
private final JWTUtil jwtUtil;
public ChatController(SimpMessageSendingOperations simpMessageSendingOperations, ChatService chatService, JWTUtil jwtUtil){
this.simpMessageSendingOperations = simpMessageSendingOperations;
this.chatService = chatService;
this.jwtUtil = jwtUtil;
}
// @GetMapping("/chat/enter/{lectureId}")
// public ResponseEntity<?> enter(@PathVariable long lectureId){
// List<ChatUserDto> chatUsers = chatService.findChatUsers(lectureId);
//
// return new ResponseEntity<>(chatUsers, HttpStatus.OK);
// }
// @MessageMapping("/hello/{channelId}")
// @SendTo("/sub/channel/{channelId}")
// public ChatUserDto hello(@DestinationVariable long channelId, SimpMessageHeaderAccessor simpMessageHeaderAccessor, @Header("Authorization") String token){
// String sessionId = simpMessageHeaderAccessor.getSessionId();
//
// System.out.println("session" + sessionId);
//
// long userId = Long.parseLong(jwtUtil.getUserId(token));
//
// chatService.saveChatUserInfo(userId, channelId, sessionId);
//
// return chatService.getChatUserInfo(userId);
// }
@MessageMapping("/message/{lectureId}")
@SendTo("/sub/channel/{lectureId}")
public MessageDto sendMessage(@DestinationVariable long lectureId, MessageDto messageDto){return messageDto;}
@MessageMapping("/quiz/{lectureId}")
@SendTo("/sub/channel/{lectureId}")
public QuizDto quizStart(@DestinationVariable long lectureId, QuizDto quizDto){
return quizDto;
}
// @EventListener
// public void handleWebSocketDisconnectListener(SessionDisconnectEvent event){
// StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
// String sessionId = headerAccessor.getSessionId();
//
//
// ChatUserDto chatUserDto = chatService.getChatUserInfo(sessionId);
//
//
// if(chatService.checkTeacher(chatUserDto)){
// chatService.closeChatRoom(chatUserDto.getLectureId());
// simpMessageSendingOperations.convertAndSend("/sub/channel/" + chatUserDto.getLectureId(), "강의가 종료 됐습니다.");
// return;
// }
//
// chatService.deleteChatUserInfo(chatUserDto.getUserId());
// simpMessageSendingOperations.convertAndSend("/sub/channel/" + chatUserDto.getLectureId(), chatUserDto);
// }
}

View File

@ -0,0 +1,14 @@
package com.edufocus.edufocus.ws.entity.dto;
import lombok.*;
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ChatUserDto {
long userId;
long lectureId;
String name;
}

View File

@ -0,0 +1,13 @@
package com.edufocus.edufocus.ws.entity.dto;
import lombok.*;
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class HelloDto {
long lectureId;
String name;
}

View File

@ -0,0 +1,14 @@
package com.edufocus.edufocus.ws.entity.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class MessageDto {
long lectureId;
long userId;
String name;
String content;
}

View File

@ -0,0 +1,13 @@
package com.edufocus.edufocus.ws.entity.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class QuizDto {
int lectureId;
int userId;
int quizSetId;
}

View File

@ -0,0 +1,33 @@
package com.edufocus.edufocus.ws.entity.vo;
import com.edufocus.edufocus.lecture.entity.Lecture;
import com.edufocus.edufocus.user.model.entity.User;
import com.edufocus.edufocus.ws.entity.dto.ChatUserDto;
import jakarta.persistence.*;
import lombok.*;
@Entity
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ChatUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
int id;
@Column
String sessionId;
@OneToOne
User user;
@ManyToOne
Lecture lecture;
public ChatUserDto makeChatUserDto(){
return ChatUserDto.builder()
.userId(user.getId())
.name(user.getName())
.lectureId(lecture.getId())
.build();
}
}

View File

@ -0,0 +1,15 @@
package com.edufocus.edufocus.ws.repository;
import com.edufocus.edufocus.ws.entity.vo.ChatUser;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface ChatUserRepository extends JpaRepository<ChatUser, Long> {
public ChatUser findBySessionId(String sessionId);
public List<ChatUser> findByLectureId(long lectureId);
@Query("delete from ChatUser c where c.lecture.id=:lectureId")
public void deleteByLectureId(long lectureId);
}

View File

@ -0,0 +1,15 @@
package com.edufocus.edufocus.ws.service;
import com.edufocus.edufocus.ws.entity.dto.ChatUserDto;
import java.util.List;
public interface ChatService {
public void saveChatUserInfo(long userId, long channelId, String sessionId);
public ChatUserDto getChatUserInfo(long userId);
public ChatUserDto getChatUserInfo(String sessionId);
public List<ChatUserDto> findChatUsers(long lectureId);
public boolean checkTeacher(ChatUserDto chatUser);
public void closeChatRoom(long chatRoomId);
public void deleteChatUserInfo(long userId);
}

View File

@ -0,0 +1,83 @@
package com.edufocus.edufocus.ws.service;
import com.edufocus.edufocus.lecture.entity.Lecture;
import com.edufocus.edufocus.lecture.repository.LectureRepository;
import com.edufocus.edufocus.user.model.entity.User;
import com.edufocus.edufocus.user.model.repository.UserRepository;
import com.edufocus.edufocus.ws.entity.dto.ChatUserDto;
import com.edufocus.edufocus.ws.entity.vo.ChatUser;
import com.edufocus.edufocus.ws.repository.ChatUserRepository;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class ChatServiceImpl implements ChatService{
private final ChatUserRepository chatUserRepository;
private final UserRepository userRepository;
private final LectureRepository lectureRepository;
public ChatServiceImpl(ChatUserRepository chatUserRepository, UserRepository userRepository, LectureRepository lectureRepository) {
this.chatUserRepository = chatUserRepository;
this.userRepository = userRepository;
this.lectureRepository = lectureRepository;
}
@Override
public void saveChatUserInfo(long userId, long lectureId, String sessionId) {
User user = userRepository.getReferenceById(userId);
Lecture lecture = lectureRepository.getReferenceById(lectureId);
ChatUser chatUser = ChatUser.builder()
.user(user)
.lecture(lecture)
.sessionId(sessionId)
.build();
chatUserRepository.save(chatUser);
}
@Override
public ChatUserDto getChatUserInfo(long userId) {
ChatUser chatUser = chatUserRepository.findById(userId).orElseThrow(IllegalArgumentException::new);
return chatUser.makeChatUserDto();
}
@Override
public ChatUserDto getChatUserInfo(String sessionId) {
ChatUser chatUser = chatUserRepository.findBySessionId(sessionId);
return chatUser.makeChatUserDto();
}
@Override
public List<ChatUserDto> findChatUsers(long lectureId) {
return chatUserRepository.findByLectureId(lectureId)
.stream()
.map(ChatUser::makeChatUserDto)
.collect(Collectors.toList());
}
@Override
public boolean checkTeacher(ChatUserDto chatUser) {
Lecture lecture = lectureRepository.findByIdAndUserId(chatUser.getLectureId(), chatUser.getUserId());
return lecture != null;
}
@Override
public void closeChatRoom(long lectureId) {
chatUserRepository.deleteByLectureId(lectureId);
}
@Override
public void deleteChatUserInfo(long userId) {
ChatUser chatUser = chatUserRepository.getReferenceById(userId);
chatUserRepository.delete(chatUser);
}
}