Skip to content

Commit

Permalink
Feat/chat group http (#97)
Browse files Browse the repository at this point in the history
* feat/chat-group-http-1: 채팅서비스 테스트를 위한 임시 시큐리티 허용

* feat/chat-group-http-2: 채팅방 엔티티 세팅
- ChatRoom:
- ChatRoom을 일대일, 그룹이 함께 있는 하나의 DB로 사용할 예정이기 때문에 기준이 될 수 있는 필드값에 채팅방 이름과 채팅방 타입 할당
- 생성일시 자동으로 찍히게 BaseTimeEntity 상속
- ChatRoomSetting:
- 그룹 채팅방일 경우에 활성화되는 그룹 채팅방 설정 클래스
- 그룹 채팅방 한줄 소개, 최대, 최소 인원수

* feat/chat-group-http-3: 채팅 Controller, Service
- ChatController:
- RESTFul API에 맞게 POST URL 매핑
- 최대 인원수와 최소 인원수를 String으로 받는데 이는 null 처리를 하기 위함임
- ChatRoomService:
- 그룹 채팅방 생성 메서드 생성
- 모든 입력값에 대해서 NotNull 익셉션 핸들링
- 최대인원수, 최소인원수는 int 타입으로 변환 후 DB에 저장됨

* feat/chat-group-http-4: 채팅 Exception
- 그룹 채팅방 생성 시에 중복된 채팅방 명이 있을 때 : 409 Conflict
- 그룹 채팅방 생성 시에 최소, 최대 인원 수를 만족시키지 않았을 때 : 400 Bad Request
- 그룹 채팅방 생성 시에 필수 입력사항을 입력하지 않았을 때 : 400 Bad Request

* style: 린팅 오류 수정
- ChatController에서의 공백

* refactor: Chatroom 엔티티 수정 및 필드명 개선
- 피드백 반영 Chatroom 엔티티 명 수정 및 필드명 개선
- URL 통일성 있게 복수형으로 변화
- 변경 .yml 적용

* fix: Linting 오류 수정
- Spotless 미적용으로 인한 오류 수정

* refactor: POST요청의 경우 @RequestBody로 요청을 받자
- 피드백 반영 POST요청 시에 @RequstBody로 요청 받기
- 채팅방 생성 요청 DTO, 채팅방 생성 응답 DTO 분리
- GroupChatroomRequestDto:
- @min, @max을 이용해 최대, 최소 인원수 지정
- 채팅방 생성 복수형 명칭 -> 테스트 환경 일시적 허용 설정 적용
  • Loading branch information
KooSuYeon authored Apr 30, 2024
1 parent 8e325bb commit 9e052a6
Show file tree
Hide file tree
Showing 14 changed files with 282 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/main/java/com/dife/api/GlobalExceptionHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,24 @@ public ResponseEntity<ExceptionResonse> handleConnectException(
return ResponseEntity.status(BAD_REQUEST)
.body(new ExceptionResonse(false, exception.getMessage()));
}

@ExceptionHandler(ChatroomCountException.class)
public ResponseEntity<ExceptionResonse> handleChatroomCountException(
ChatroomCountException exception) {
return ResponseEntity.status(BAD_REQUEST)
.body(new ExceptionResonse(false, exception.getMessage()));
}

@ExceptionHandler(ChatroomDuplicateException.class)
public ResponseEntity<ExceptionResonse> handleChatroomDuplicateException(
ChatroomDuplicateException exception) {
return ResponseEntity.status(CONFLICT)
.body(new ExceptionResonse(false, exception.getMessage()));
}

@ExceptionHandler(ChatroomException.class)
public ResponseEntity<ExceptionResonse> handleChatroomException(ChatroomException exception) {
return ResponseEntity.status(BAD_REQUEST)
.body(new ExceptionResonse(false, exception.getMessage()));
}
}
1 change: 1 addition & 0 deletions src/main/java/com/dife/api/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
41 changes: 41 additions & 0 deletions src/main/java/com/dife/api/controller/ChatController.java
Original file line number Diff line number Diff line change
@@ -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<GroupChatroomResponseDto> 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));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.dife.api.exception;

public class ChatroomCountException extends IllegalArgumentException {

public ChatroomCountException() {
super("그룹 채팅방의 최소 인원은 3명, 최대 인원은 30명입니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.dife.api.exception;

public class ChatroomDuplicateException extends RuntimeException {
public ChatroomDuplicateException() {
super("이미 해당 채팅방이름을 가진 채팅방이 존재합니다.");
}
}
8 changes: 8 additions & 0 deletions src/main/java/com/dife/api/exception/ChatroomException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.dife.api.exception;

public class ChatroomException extends IllegalArgumentException {

public ChatroomException(String message) {
super(message);
}
}
1 change: 1 addition & 0 deletions src/main/java/com/dife/api/jwt/JWTFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/com/dife/api/model/Chatroom.java
Original file line number Diff line number Diff line change
@@ -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;
}
15 changes: 15 additions & 0 deletions src/main/java/com/dife/api/model/ChatroomSetting.java
Original file line number Diff line number Diff line change
@@ -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;
}
6 changes: 6 additions & 0 deletions src/main/java/com/dife/api/model/ChatroomType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.dife.api.model;

public enum ChatroomType {
GROUP,
SINGLE
}
36 changes: 36 additions & 0 deletions src/main/java/com/dife/api/model/dto/GroupChatroomRequestDto.java
Original file line number Diff line number Diff line change
@@ -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;
}
39 changes: 39 additions & 0 deletions src/main/java/com/dife/api/model/dto/GroupChatroomResponseDto.java
Original file line number Diff line number Diff line change
@@ -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();
}
}
11 changes: 11 additions & 0 deletions src/main/java/com/dife/api/repository/ChatroomRepository.java
Original file line number Diff line number Diff line change
@@ -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<Chatroom, Long> {

boolean existsByName(String name);
}
63 changes: 63 additions & 0 deletions src/main/java/com/dife/api/service/ChatroomService.java
Original file line number Diff line number Diff line change
@@ -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;
}
}

0 comments on commit 9e052a6

Please sign in to comment.