diff --git a/src/main/java/com/dife/api/GlobalExceptionHandler.java b/src/main/java/com/dife/api/GlobalExceptionHandler.java index ea87daa3..4a7c62ad 100644 --- a/src/main/java/com/dife/api/GlobalExceptionHandler.java +++ b/src/main/java/com/dife/api/GlobalExceptionHandler.java @@ -78,4 +78,24 @@ public ResponseEntity handleConnectException( return ResponseEntity.status(BAD_REQUEST) .body(new ExceptionResonse(false, exception.getMessage())); } + + @ExceptionHandler(ChatroomCountException.class) + public ResponseEntity handleChatroomCountException( + ChatroomCountException exception) { + return ResponseEntity.status(BAD_REQUEST) + .body(new ExceptionResonse(false, exception.getMessage())); + } + + @ExceptionHandler(ChatroomDuplicateException.class) + public ResponseEntity handleChatroomDuplicateException( + ChatroomDuplicateException exception) { + return ResponseEntity.status(CONFLICT) + .body(new ExceptionResonse(false, exception.getMessage())); + } + + @ExceptionHandler(ChatroomException.class) + public ResponseEntity handleChatroomException(ChatroomException exception) { + return ResponseEntity.status(BAD_REQUEST) + .body(new ExceptionResonse(false, exception.getMessage())); + } } diff --git a/src/main/java/com/dife/api/config/SecurityConfig.java b/src/main/java/com/dife/api/config/SecurityConfig.java index 1ee57702..490a07c1 100644 --- a/src/main/java/com/dife/api/config/SecurityConfig.java +++ b/src/main/java/com/dife/api/config/SecurityConfig.java @@ -59,6 +59,7 @@ public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Excepti .requestMatchers( "/swagger-ui/**", "/api/v1/api-docs", + "/api/chats/**", "/api/members/register", "/api/members/change-password", "/api/members/login") diff --git a/src/main/java/com/dife/api/controller/ChatController.java b/src/main/java/com/dife/api/controller/ChatController.java new file mode 100644 index 00000000..d7a6b56c --- /dev/null +++ b/src/main/java/com/dife/api/controller/ChatController.java @@ -0,0 +1,41 @@ +package com.dife.api.controller; + +import com.dife.api.model.Chatroom; +import com.dife.api.model.dto.GroupChatroomRequestDto; +import com.dife.api.model.dto.GroupChatroomResponseDto; +import com.dife.api.service.ChatroomService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +@Controller +@RequiredArgsConstructor +@RequestMapping("/api/chats") +@Slf4j +@Tag(name = "Chat API", description = "Chat API") +public class ChatController { + + private final ChatroomService chatroomService; + + @Operation(summary = "그룹 채팅방 생성", description = "사용자가 그룹 채팅방 생성") + @PostMapping + public ResponseEntity createGroupChatroom( + @RequestBody( + description = "채팅방 이름, 한줄소개, 최소 인원수, 최대 인원수를 포함하는 그룹 채팅방 생성 데이터", + required = true, + content = @Content(schema = @Schema(implementation = GroupChatroomRequestDto.class))) + GroupChatroomRequestDto dto) { + + Chatroom chatroom = chatroomService.createGroupChatroom(dto); + + return ResponseEntity.status(HttpStatus.CREATED).body(new GroupChatroomResponseDto(chatroom)); + } +} diff --git a/src/main/java/com/dife/api/exception/ChatroomCountException.java b/src/main/java/com/dife/api/exception/ChatroomCountException.java new file mode 100644 index 00000000..41cb05cc --- /dev/null +++ b/src/main/java/com/dife/api/exception/ChatroomCountException.java @@ -0,0 +1,8 @@ +package com.dife.api.exception; + +public class ChatroomCountException extends IllegalArgumentException { + + public ChatroomCountException() { + super("그룹 채팅방의 최소 인원은 3명, 최대 인원은 30명입니다."); + } +} diff --git a/src/main/java/com/dife/api/exception/ChatroomDuplicateException.java b/src/main/java/com/dife/api/exception/ChatroomDuplicateException.java new file mode 100644 index 00000000..f46c2f2e --- /dev/null +++ b/src/main/java/com/dife/api/exception/ChatroomDuplicateException.java @@ -0,0 +1,7 @@ +package com.dife.api.exception; + +public class ChatroomDuplicateException extends RuntimeException { + public ChatroomDuplicateException() { + super("이미 해당 채팅방이름을 가진 채팅방이 존재합니다."); + } +} diff --git a/src/main/java/com/dife/api/exception/ChatroomException.java b/src/main/java/com/dife/api/exception/ChatroomException.java new file mode 100644 index 00000000..8323b8fe --- /dev/null +++ b/src/main/java/com/dife/api/exception/ChatroomException.java @@ -0,0 +1,8 @@ +package com.dife.api.exception; + +public class ChatroomException extends IllegalArgumentException { + + public ChatroomException(String message) { + super(message); + } +} diff --git a/src/main/java/com/dife/api/jwt/JWTFilter.java b/src/main/java/com/dife/api/jwt/JWTFilter.java index 211afc94..354ec4c8 100644 --- a/src/main/java/com/dife/api/jwt/JWTFilter.java +++ b/src/main/java/com/dife/api/jwt/JWTFilter.java @@ -42,6 +42,7 @@ protected void doFilterInternal( || servletPath.equals("/api/members/change-password") || servletPath.equals("/api/members/login") || servletPath.startsWith("/swagger-ui") + || servletPath.startsWith("/api/chat") || servletPath.equals("/api/v1/api-docs")) { filterChain.doFilter(request, response); return; diff --git a/src/main/java/com/dife/api/model/Chatroom.java b/src/main/java/com/dife/api/model/Chatroom.java new file mode 100644 index 00000000..d2ad3e52 --- /dev/null +++ b/src/main/java/com/dife/api/model/Chatroom.java @@ -0,0 +1,26 @@ +package com.dife.api.model; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "chatroom") +public class Chatroom extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + private ChatroomType chatroomType; + + @Embedded private ChatroomSetting setting; +} diff --git a/src/main/java/com/dife/api/model/ChatroomSetting.java b/src/main/java/com/dife/api/model/ChatroomSetting.java new file mode 100644 index 00000000..22fa71cf --- /dev/null +++ b/src/main/java/com/dife/api/model/ChatroomSetting.java @@ -0,0 +1,15 @@ +package com.dife.api.model; + +import jakarta.persistence.Embeddable; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Embeddable +public class ChatroomSetting { + + private String description; + private Integer min_count; + private Integer max_count; +} diff --git a/src/main/java/com/dife/api/model/ChatroomType.java b/src/main/java/com/dife/api/model/ChatroomType.java new file mode 100644 index 00000000..a0f538f4 --- /dev/null +++ b/src/main/java/com/dife/api/model/ChatroomType.java @@ -0,0 +1,6 @@ +package com.dife.api.model; + +public enum ChatroomType { + GROUP, + SINGLE +} diff --git a/src/main/java/com/dife/api/model/dto/GroupChatroomRequestDto.java b/src/main/java/com/dife/api/model/dto/GroupChatroomRequestDto.java new file mode 100644 index 00000000..834a29b6 --- /dev/null +++ b/src/main/java/com/dife/api/model/dto/GroupChatroomRequestDto.java @@ -0,0 +1,36 @@ +package com.dife.api.model.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Schema(description = "그룹 채팅방 생성 요청 객체") +public class GroupChatroomRequestDto { + + @NotNull(message = "그룹 채팅방 이름을 입력해주세요!") + @Schema(description = "그룹 채팅방 이름", example = "21학번 모여라") + private String name; + + @NotNull(message = "그룹 채팅방의 한줄 소개를 입력해주세요!") + @Schema(description = "그룹 채팅방 한줄 소개", example = "21학번 정보 공유 및 잡담 채팅방") + private String description; + + @NotNull(message = "그룹 채팅방의 최대 인원수를 입력해주세요!") + @Max(value = 30, message = "최소 인원수는 30명 이하여야 합니다.") + @Schema(description = "그룹 채팅방 최대 인원수", example = "30") + private Integer max_count; + + @NotNull(message = "그룹 채팅방의 최소 인원수를 입력해주세요!") + @Min(value = 3, message = "최소 인원수는 3명 이상이어야 합니다.") + @Schema(description = "그룹 채팅방 최소 인원수", example = "3") + private Integer min_count; +} diff --git a/src/main/java/com/dife/api/model/dto/GroupChatroomResponseDto.java b/src/main/java/com/dife/api/model/dto/GroupChatroomResponseDto.java new file mode 100644 index 00000000..de573ded --- /dev/null +++ b/src/main/java/com/dife/api/model/dto/GroupChatroomResponseDto.java @@ -0,0 +1,39 @@ +package com.dife.api.model.dto; + +import com.dife.api.model.Chatroom; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; +import lombok.*; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Schema(description = "그룹 채팅방 응답 객체") +public class GroupChatroomResponseDto { + + @Schema(description = "그룹 채팅방 생성 성공여부", example = "true") + private Boolean success; + + private Long roomId; + + @NotNull(message = "그룹 채팅방 이름을 입력해주세요!") + @Schema(description = "그룹 채팅방 이름", example = "21학번 모여라") + private String name; + + @NotNull(message = "그룹 채팅방의 한줄 소개를 입력해주세요!") + @Schema(description = "그룹 채팅방 한줄 소개", example = "21학번 정보 공유 및 잡담 채팅방") + private String description; + + @Schema(description = "채팅방 생성 일시") + private LocalDateTime created; + + public GroupChatroomResponseDto(Chatroom chatroom) { + this.success = true; + this.roomId = chatroom.getId(); + this.name = chatroom.getName(); + this.description = chatroom.getSetting().getDescription(); + this.created = chatroom.getCreated(); + } +} diff --git a/src/main/java/com/dife/api/repository/ChatroomRepository.java b/src/main/java/com/dife/api/repository/ChatroomRepository.java new file mode 100644 index 00000000..4182e05e --- /dev/null +++ b/src/main/java/com/dife/api/repository/ChatroomRepository.java @@ -0,0 +1,11 @@ +package com.dife.api.repository; + +import com.dife.api.model.Chatroom; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ChatroomRepository extends JpaRepository { + + boolean existsByName(String name); +} diff --git a/src/main/java/com/dife/api/service/ChatroomService.java b/src/main/java/com/dife/api/service/ChatroomService.java new file mode 100644 index 00000000..ed1aba20 --- /dev/null +++ b/src/main/java/com/dife/api/service/ChatroomService.java @@ -0,0 +1,63 @@ +package com.dife.api.service; + +import com.dife.api.exception.ChatroomCountException; +import com.dife.api.exception.ChatroomDuplicateException; +import com.dife.api.exception.ChatroomException; +import com.dife.api.model.*; +import com.dife.api.model.dto.GroupChatroomRequestDto; +import com.dife.api.repository.ChatroomRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional +@Slf4j +public class ChatroomService { + + @Autowired private final ChatroomRepository chatRoomRepository; + + public Chatroom createGroupChatroom(GroupChatroomRequestDto dto) { + + String name = dto.getName(); + String description = dto.getDescription(); + Integer max_count = dto.getMax_count(); + Integer min_count = dto.getMin_count(); + + Chatroom chatroom = new Chatroom(); + if (chatRoomRepository.existsByName(name)) { + throw new ChatroomDuplicateException(); + } + if (name == null || name.isEmpty()) { + throw new ChatroomException("채팅방 이름은 필수사항입니다."); + } + chatroom.setName(name); + chatroom.setChatroomType(ChatroomType.GROUP); + + ChatroomSetting setting = new ChatroomSetting(); + + if (min_count == null || max_count == null) { + throw new ChatroomException("채팅방 인원 설정은 필수사항입니다."); + } + + if (max_count > 30 || min_count < 3) { + throw new ChatroomCountException(); + } + setting.setMax_count(max_count); + setting.setMin_count(min_count); + + if (description == null || description.isEmpty()) { + throw new ChatroomException("채팅방 이름은 필수사항입니다."); + } + setting.setDescription(description); + + chatroom.setSetting(setting); + + chatRoomRepository.save(chatroom); + + return chatroom; + } +}