Skip to content

Commit

Permalink
Merge pull request #95 from Dev-Race/refactor/#94
Browse files Browse the repository at this point in the history
[#94] Refactor: 입장 Rest API를 WebSocket API에 통합
  • Loading branch information
tkguswls1106 authored May 25, 2024
2 parents 32f09a9 + 3fc9232 commit dd87583
Show file tree
Hide file tree
Showing 13 changed files with 175 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.sajang.devracebackend.config.RabbitConfig;
import com.sajang.devracebackend.dto.problem.ProblemSaveRequestDto;
import com.sajang.devracebackend.dto.room.RoomSaveResponseDto;
import com.sajang.devracebackend.dto.room.RoomEnterRequestDto;
import com.sajang.devracebackend.dto.room.RoomWaitRequestDto;
import com.sajang.devracebackend.dto.room.RoomWaitResponseDto;
import com.sajang.devracebackend.dto.userroom.UserPassRequestDto;
Expand Down Expand Up @@ -42,16 +41,6 @@ public ResponseEntity<ResponseData<RoomSaveResponseDto>> createRoom(@RequestBody
return ResponseData.toResponseEntity(ResponseCode.CREATED_ROOM, roomSaveResponseDto);
}

@PostMapping("/rooms/{roomId}")
@Operation(summary = "방 입장 시작 [jwt O]", description = "userIdList : 방장을 제외한 나머지 입장자들 목록")
public ResponseEntity<ResponseData> usersEnterRoom(
@PathVariable(value = "roomId") Long roomId, // value=""를 작성해주어야만, Swagger에서 api테스트할때 이름값이 뜸.
@RequestBody RoomEnterRequestDto roomEnterRequestDto) {

userRoomService.usersEnterRoom(roomId, roomEnterRequestDto);
return ResponseData.toResponseEntity(ResponseCode.CREATED_USERROOM);
}

@GetMapping("/rooms/{roomId}")
@Operation(summary = "문제풀이 페이지 정보 조회 [jwt O]")
public ResponseEntity<ResponseData<SolvingPageResponseDto>> loadSolvingPage(@PathVariable(value = "roomId") Long roomId) { // value=""를 작성해주어야만, Swagger에서 api테스트할때 이름값이 뜸.
Expand All @@ -67,25 +56,32 @@ public ResponseEntity<ResponseData<RoomCheckAccessResponseDto>> checkAccess(@Pat
}

@GetMapping("/rooms/{roomId}/state-check")
@Operation(summary = "방 상태 검사 [jwt O]")
@Operation(summary = "방 상태 검사 [jwt O]", description = "dtoList index==0 : 방장 / dtoList index==others : 방장 외 대기자들 nickname & createdTime 기준 오름차순 정렬")
public ResponseEntity<ResponseData<RoomCheckStateResponseDto>> checkState(@PathVariable(value = "roomId") Long roomId) {
RoomCheckStateResponseDto roomCheckStateResponseDto = roomService.checkState(roomId);
return ResponseData.toResponseEntity(ResponseCode.READ_USERROOM, roomCheckStateResponseDto);
}

@PutMapping("/room/{roomId}")
@PostMapping("/rooms/{roomId}") // 의미상 PUT보단 POST가 더 적합하다고 판단했음.
@Operation(summary = "문제풀이 실패 및 성공 [jwt O]", description = "isRetry==0 : 첫풀이 경우 / isRetry==1 : 재풀이 경우")
public ResponseEntity<ResponseData> passSolvingProblem(
@PathVariable(value = "roomId") Long roomId,
@RequestBody UserPassRequestDto userPassRequestDto) {
userRoomService.passSolvingProblem(roomId, userPassRequestDto);
return ResponseData.toResponseEntity(ResponseCode.UPDATE_USERROOM);
return ResponseData.toResponseEntity(ResponseCode.UPDATE_USERROOM); // 비록 POST이지만, 비즈니스 로직은 update임.
}

@PutMapping("/rooms/{roomId}")
@Operation(summary = "방 입장 대기열 나가기 [jwt O]")
public ResponseEntity<ResponseData> userStopWaitRoom(@PathVariable(value = "roomId") Long roomId) {
userRoomService.userStopWaitRoom(roomId);
return ResponseData.toResponseEntity(ResponseCode.UPDATE_ROOM);
}

@MessageMapping("wait.enter") // 웹소켓 메시지 처리 (백엔드로 '/pub/wait.enter'를 호출시 이 브로커에서 처리)
public void userWaitRoom(@Payload RoomWaitRequestDto roomWaitRequestDto) {
// '/exchange/wait.exchange/waitingroom.{roomId}' 구독되어있는 프론트엔드에게 메세지 전달.
RoomWaitResponseDto roomWaitResponseDto = roomService.userWaitRoom(roomWaitRequestDto);
RoomWaitResponseDto roomWaitResponseDto = userRoomService.userWaitRoom(roomWaitRequestDto);
rabbitTemplate.convertAndSend(RabbitConfig.WAIT_EXCHANGE_NAME, "waitingroom." + roomWaitResponseDto.getRoomId(), roomWaitResponseDto);
}

Expand Down
28 changes: 27 additions & 1 deletion src/main/java/com/sajang/devracebackend/domain/Room.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.sajang.devracebackend.domain.common.BaseEntity;
import com.sajang.devracebackend.domain.enums.RoomState;
import com.sajang.devracebackend.domain.mapping.UserRoom;
import com.sajang.devracebackend.util.LongListConverter;
import com.sajang.devracebackend.util.StringListConverter;
import jakarta.persistence.*;
import lombok.*;
Expand All @@ -26,6 +27,9 @@ public class Room extends BaseEntity implements Serializable{
@Column(name = "link", unique = true)
private String link;

@Convert(converter = LongListConverter.class) // DB에는 String으로 저장됨.
private List<Long> waiting = new ArrayList<>(); // 0인덱스에는 무조건 방장의 userId가 들어갈것.

@Convert(converter = StringListConverter.class) // DB에는 String으로 저장됨.
private List<String> ranking = new ArrayList<>();

Expand All @@ -45,13 +49,35 @@ public class Room extends BaseEntity implements Serializable{
public Room(String link, Problem problem) {
// 이 빌더는 Room 생성때만 사용할 용도
this.link = link;
this.waiting = new ArrayList<>(); // 초기값 빈배열인 문자열 -> "__null__"
this.ranking = new ArrayList<>(); // 초기값 빈배열인 문자열 -> "__null__"
this.roomState = RoomState.WAIT; // 초기값 WAIT
this.problem = problem;
}


public void updateRanking(String nickname) {
public void addWaiting(Long userId, Boolean isManager) {
if(isManager == true) { // 방장인 경우, 리스트의 맨앞에 추가.
if(this.waiting.contains(userId)) {
this.waiting.remove(userId);
}
this.waiting.add(0, userId);
}
else if(!this.waiting.contains(userId)) { // 방장이 아니며, 리스트에 없는 일반 사용자인 경우
this.waiting.add(userId);
}
}

public void deleteWaiting(Long userId, Boolean isAllDelete) {
if(isAllDelete == true) {
this.waiting.clear();
}
else {
this.waiting.remove(userId);
}
}

public void addRanking(String nickname) {
this.ranking.add(nickname);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package com.sajang.devracebackend.dto.room;

import com.sajang.devracebackend.domain.enums.RoomState;
import com.sajang.devracebackend.dto.user.UserResponseDto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class RoomCheckStateResponseDto {

private RoomState roomState;
private String link;
private List<UserResponseDto> userResponseDtoList;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@
@NoArgsConstructor
public class RoomWaitRequestDto {

// 방
private Long roomId;

// 대기
private Long userId; // 대기자 userId
private Boolean isManager; // 방장 여부

// 입장
private Boolean isEnter; // 입장 여부
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,16 @@
@AllArgsConstructor
public class RoomWaitResponseDto {

// 방
private Long roomId;

// 대기
private Long userId; // 대기자 userId
private String nickname; // 대기자 이름
private String imageUrl; // 대기자 이미지url
private Boolean isManager; // 방장 여부

// 입장
private Boolean isEnter; // 입장 여부
private LocalDateTime createdTime;
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public enum ResponseCode {
// Room 성공 응답
CREATED_ROOM(StatusItem.CREATED, MessageItem.CREATED_ROOM),
READ_ROOM(StatusItem.OK, MessageItem.READ_ROOM),
UPDATE_ROOM(StatusItem.NO_CONTENT, MessageItem.UPDATE_ROOM),

// Room 실패 응답
NOT_FOUND_ROOM(StatusItem.NOT_FOUND, MessageItem.NOT_FOUND_ROOM),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class MessageItem {
// < Room >
public static final String CREATED_ROOM = "SUCCESS - 방 생성 성공";
public static final String READ_ROOM = "SUCCESS - 방 조회 성공";
public static final String UPDATE_ROOM = "SUCCESS - 방 정보 수정 성공";

public static final String NOT_FOUND_ROOM = "ERROR - 존재하지 않는 방 조회 에러";
public static final String BAD_REQUEST_ROOM = "ERROR - 잘못된 방 요청 에러";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
import com.sajang.devracebackend.dto.problem.ProblemSaveRequestDto;
import com.sajang.devracebackend.dto.room.RoomCheckStateResponseDto;
import com.sajang.devracebackend.dto.room.RoomSaveResponseDto;
import com.sajang.devracebackend.dto.room.RoomWaitRequestDto;
import com.sajang.devracebackend.dto.room.RoomWaitResponseDto;

import java.io.IOException;

public interface RoomService {
Room findRoom(Long roomId);
RoomSaveResponseDto createRoom(ProblemSaveRequestDto problemSaveRequestDto) throws IOException;
RoomWaitResponseDto userWaitRoom(RoomWaitRequestDto roomWaitRequestDto);
RoomCheckStateResponseDto checkState(Long roomId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

import com.sajang.devracebackend.domain.Room;
import com.sajang.devracebackend.domain.User;
import com.sajang.devracebackend.dto.room.RoomEnterRequestDto;
import com.sajang.devracebackend.dto.room.RoomWaitRequestDto;
import com.sajang.devracebackend.dto.room.RoomWaitResponseDto;
import com.sajang.devracebackend.dto.userroom.UserPassRequestDto;
import com.sajang.devracebackend.dto.userroom.RoomCheckAccessResponseDto;
import com.sajang.devracebackend.dto.userroom.SolvingPageResponseDto;

public interface UserRoomService {
void createUserRoom(User user, Room room);
void usersEnterRoom(Long roomId, RoomEnterRequestDto roomEnterRequestDto);
RoomWaitResponseDto userWaitRoom(RoomWaitRequestDto roomWaitRequestDto);
void usersEnterRoom(Long roomId);
void userStopWaitRoom(Long roomId);
SolvingPageResponseDto loadSolvingPage(Long roomId);
RoomCheckAccessResponseDto checkAccess(Long roomId);
void passSolvingProblem(Long roomId, UserPassRequestDto userPassRequestDto);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,31 @@
import com.sajang.devracebackend.dto.problem.ProblemSaveRequestDto;
import com.sajang.devracebackend.dto.room.RoomCheckStateResponseDto;
import com.sajang.devracebackend.dto.room.RoomSaveResponseDto;
import com.sajang.devracebackend.dto.room.RoomWaitRequestDto;
import com.sajang.devracebackend.dto.room.RoomWaitResponseDto;
import com.sajang.devracebackend.repository.ProblemRepository;
import com.sajang.devracebackend.repository.RoomRepository;
import com.sajang.devracebackend.dto.user.UserResponseDto;
import com.sajang.devracebackend.repository.*;
import com.sajang.devracebackend.response.exception.exception404.NoSuchRoomException;
import com.sajang.devracebackend.service.ProblemService;
import com.sajang.devracebackend.service.RoomService;
import com.sajang.devracebackend.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class RoomServiceImpl implements RoomService {

private final UserService userService;
private final ProblemService problemService;
private final ProblemRepository problemRepository;
private final UserRepository userRepository;
private final RoomRepository roomRepository;
private final ProblemRepository problemRepository;


@Transactional(readOnly = true)
Expand Down Expand Up @@ -69,27 +69,34 @@ public RoomSaveResponseDto createRoom(ProblemSaveRequestDto problemSaveRequestDt
return roomSaveResponseDto;
}

@Transactional
@Override
public RoomWaitResponseDto userWaitRoom(RoomWaitRequestDto roomWaitRequestDto) {
User user = userService.findUser(roomWaitRequestDto.getUserId());
RoomWaitResponseDto roomWaitResponseDto = RoomWaitResponseDto.builder()
.roomId(roomWaitRequestDto.getRoomId())
.userId(roomWaitRequestDto.getUserId())
.nickname(user.getNickname())
.isManager(roomWaitRequestDto.getIsManager())
.createdTime(LocalDateTime.now()) // 시간을 수동으로 직접 넣어줌.
.build();

return roomWaitResponseDto;
}

@Transactional(readOnly = true)
@Override
public RoomCheckStateResponseDto checkState(Long roomId) {
Room room = findRoom(roomId);
List<Long> waitUserIdList = room.getWaiting();
List<User> waitUserList = userRepository.findByIdIn(waitUserIdList);
List<UserResponseDto> userResponseDtoList = waitUserList.stream()
.map(UserResponseDto::new)
.collect(Collectors.toList());

List<UserResponseDto> sortedUserResponseDtoList = new ArrayList<>();
if(userResponseDtoList.size() > 1) {
// 방장인 맨앞 인덱스를 제외하고 나머지 인덱스들을 정렬.
sortedUserResponseDtoList.addAll(userResponseDtoList.subList(1, userResponseDtoList.size()).stream()
.sorted(Comparator.comparing(UserResponseDto::getNickname)
.thenComparing(UserResponseDto::getCreatedTime)) // nickname으로 먼저 오름차순 정렬 후, createdTime으로 오름차순 정렬.
.collect(Collectors.toList()));
// 방장을 정렬된 리스트의 맨앞에 추가.
sortedUserResponseDtoList.add(0, userResponseDtoList.get(0));
}
else {
sortedUserResponseDtoList = userResponseDtoList;
}

RoomCheckStateResponseDto roomCheckStateResponseDto = RoomCheckStateResponseDto.builder()
.roomState(room.getRoomState())
.link(room.getLink())
.userResponseDtoList(sortedUserResponseDtoList)
.build();

return roomCheckStateResponseDto;
Expand Down
Loading

0 comments on commit dd87583

Please sign in to comment.