diff --git a/boomerang/src/main/http/Comments.http b/boomerang/src/main/http/Comments.http index 764e297c..41b3be73 100644 --- a/boomerang/src/main/http/Comments.http +++ b/boomerang/src/main/http/Comments.http @@ -20,7 +20,7 @@ Content-Type: application/json Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiZW1haWwiOiJrYWthbzM3Mjk0MzgwNTIiLCJpYXQiOjE3Mjc5MzM4MjcsImV4cCI6MjQxNzI3OTMzODI3fQ.LvKK8vbExt91eIqU-rfsdvYE0JqC1MUlsK7gdRE72co { - "text": "댓글수정!" + "text": "댓글수정!" } ### delete comments diff --git a/boomerang/src/main/http/Login.http b/boomerang/src/main/http/Login.http index 01f76020..90de1984 100644 --- a/boomerang/src/main/http/Login.http +++ b/boomerang/src/main/http/Login.http @@ -5,7 +5,7 @@ POST http://localhost:8080/api/v1/auth/login/kakao Content-Type: application/json { - "access_token":"9WfcdG_SdMnU2oM_GuhKNXCDLrfoN4LIAAAAAQopyWAAAAGTBlsa1OiSikwhugC4" + "access_token": "9WfcdG_SdMnU2oM_GuhKNXCDLrfoN4LIAAAAAQopyWAAAAGTBlsa1OiSikwhugC4" } @@ -15,5 +15,5 @@ Content-Type: application/json Authorization: {{Authorization}} { - "new_nickname":"aaa" + "new_nickname": "aaa" } diff --git a/boomerang/src/main/java/boomerang/board/controller/BoardController.java b/boomerang/src/main/java/boomerang/board/controller/BoardController.java index abe66c81..80811195 100644 --- a/boomerang/src/main/java/boomerang/board/controller/BoardController.java +++ b/boomerang/src/main/java/boomerang/board/controller/BoardController.java @@ -1,7 +1,12 @@ package boomerang.board.controller; import boomerang.board.domain.Board; -import boomerang.board.dto.*; +import boomerang.board.dto.BoardBestListRequestDto; +import boomerang.board.dto.BoardDetailResponseDto; +import boomerang.board.dto.BoardListRequestDto; +import boomerang.board.dto.BoardRequestDto; +import boomerang.board.dto.BoardResponseDto; +import boomerang.board.dto.BoardSimpleResponseDto; import boomerang.board.service.BoardService; import boomerang.comment.dto.CommentListRequestDto; import boomerang.comment.dto.CommentResponseDto; @@ -14,17 +19,26 @@ import boomerang.like.service.LikeService; import boomerang.member.domain.Member; import boomerang.member.service.MemberService; +import java.util.List; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import java.util.List; - @Slf4j @RestController @@ -37,8 +51,8 @@ public class BoardController { private final LikeService likeService; public BoardController(BoardService boardService, MemberService memberService, - CommentService commentService, - LikeService likeService) { + CommentService commentService, + LikeService likeService) { this.boardService = boardService; this.memberService = memberService; this.commentService = commentService; @@ -47,35 +61,35 @@ public BoardController(BoardService boardService, MemberService memberService, @GetMapping("/best") public ResponseEntity> getBestBoards( - @ModelAttribute BoardBestListRequestDto boardBestListRequestDto) { + @ModelAttribute BoardBestListRequestDto boardBestListRequestDto) { Page boardPage = boardService.getBestBoards(boardBestListRequestDto); Page boardResponsePage = boardPage.map(BoardResponseDto::new); return ResponseEntity.status(HttpStatus.OK) - .body(new PageResponseDto<>(boardResponsePage)); + .body(new PageResponseDto<>(boardResponsePage)); } @GetMapping public ResponseEntity> getAllBoards( - @ModelAttribute BoardListRequestDto boardListRequestDto) { + @ModelAttribute BoardListRequestDto boardListRequestDto) { Page boardPage = boardService.getAllBoards(boardListRequestDto); Page boardResponsePage = boardPage.map(BoardResponseDto::new); return ResponseEntity.status(HttpStatus.OK) - .body(new PageResponseDto<>(boardResponsePage)); + .body(new PageResponseDto<>(boardResponsePage)); } @GetMapping("/{board_id}") public ResponseEntity getBoardById( - @AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable(name = "board_id") Long boardId) { + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable(name = "board_id") Long boardId) { Board board = boardService.getBoard(boardId); PageResponseDto commentListResponseDto = new PageResponseDto<>( - commentService.getAllComment(boardId, new CommentListRequestDto()) - .map(CommentResponseDto::new)); + commentService.getAllComment(boardId, new CommentListRequestDto()) + .map(CommentResponseDto::new)); boolean isLiked = false; @@ -85,15 +99,15 @@ public ResponseEntity getBoardById( } return ResponseEntity.status(HttpStatus.OK) - .body(new BoardDetailResponseDto(board, commentListResponseDto, isLiked)); + .body(new BoardDetailResponseDto(board, commentListResponseDto, isLiked)); } @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity createBoard( - @AuthenticationPrincipal PrincipalDetails principalDetails, - @RequestPart("data") BoardRequestDto boardRequestDto, - @RequestParam("content") String content, - @RequestParam(value = "images", required = false) List images + @AuthenticationPrincipal PrincipalDetails principalDetails, + @RequestPart("data") BoardRequestDto boardRequestDto, + @RequestParam("content") String content, + @RequestParam(value = "images", required = false) List images ) { Member member = memberService.getMemberByEmail(principalDetails.getMemberEmail()); @@ -101,16 +115,16 @@ public ResponseEntity createBoard( Board createdBoard = boardService.createBoard(boardRequestDto, member, images); return ResponseEntity.status(HttpStatus.CREATED) - .body(new BoardSimpleResponseDto(createdBoard, false)); + .body(new BoardSimpleResponseDto(createdBoard, false)); } @PutMapping("/{board_id}") public ResponseEntity updateBoard( - @AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable(name = "board_id") Long boardId, - @RequestPart("data") BoardRequestDto boardRequestDto, - @RequestParam("content") String content, - @RequestParam(value = "images", required = false) List images + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable(name = "board_id") Long boardId, + @RequestPart("data") BoardRequestDto boardRequestDto, + @RequestParam("content") String content, + @RequestParam(value = "images", required = false) List images ) { Member member = memberService.getMemberByEmail(principalDetails.getMemberEmail()); @@ -118,18 +132,18 @@ public ResponseEntity updateBoard( Board updatedBoard = boardService.updateBoard(boardId, boardRequestDto, member, images); return ResponseEntity.status(HttpStatus.CREATED) - .body(new BoardSimpleResponseDto(updatedBoard, false)); + .body(new BoardSimpleResponseDto(updatedBoard, false)); } @DeleteMapping("/{board_id}") public ResponseEntity deleteBoard( - @AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable(name = "board_id") Long boardId) { + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable(name = "board_id") Long boardId) { Member member = memberService.getMemberByEmail(principalDetails.getMemberEmail()); boardService.deleteBoard(member, boardId); return ResponseEntity.status(HttpStatus.OK) - .build(); + .build(); } // GlobalException Handler 에서 처리할 경우, @@ -137,7 +151,7 @@ public ResponseEntity deleteBoard( // 때문에, 해당 에러로 Wrapping 되기 전 Controller 에서 Domain Error 를 처리해주었다 @ExceptionHandler(DomainValidationException.class) public ResponseEntity handleOptionValidException( - DomainValidationException e) { + DomainValidationException e) { log.error(e.toString()); return ResponseHelper.createErrorResponse(e.getErrorCode()); } diff --git a/boomerang/src/main/java/boomerang/board/domain/Board.java b/boomerang/src/main/java/boomerang/board/domain/Board.java index bf03191b..4bbc2b1c 100644 --- a/boomerang/src/main/java/boomerang/board/domain/Board.java +++ b/boomerang/src/main/java/boomerang/board/domain/Board.java @@ -2,25 +2,32 @@ import boomerang.IsDeleted; import boomerang.board.dto.BoardRequestDto; -import boomerang.comment.domain.Comment; -import boomerang.like.domain.Like; import boomerang.member.domain.Member; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import java.time.LocalDateTime; +import java.util.Objects; import lombok.Getter; import org.hibernate.Hibernate; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; import org.jsoup.Jsoup; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - @Getter @Entity @Table(name = "board") public class Board { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -132,9 +139,12 @@ public void decreaseCommentCount() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) + if (this == o) { + return true; + } + if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) { return false; + } Board item = (Board) o; return Objects.equals(id, item.id); } diff --git a/boomerang/src/main/java/boomerang/board/domain/Location.java b/boomerang/src/main/java/boomerang/board/domain/Location.java index 2ee3825e..83f89a63 100644 --- a/boomerang/src/main/java/boomerang/board/domain/Location.java +++ b/boomerang/src/main/java/boomerang/board/domain/Location.java @@ -3,11 +3,11 @@ import com.fasterxml.jackson.annotation.JsonValue; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; - import java.util.Objects; @Embeddable public class Location { + @Column(name = "location") private String value; @@ -32,8 +32,12 @@ public String toString() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } Location that = (Location) o; return Objects.equals(value, that.value); } diff --git a/boomerang/src/main/java/boomerang/board/dto/BoardBestListRequestDto.java b/boomerang/src/main/java/boomerang/board/dto/BoardBestListRequestDto.java index eae6b5e6..adcd01d5 100644 --- a/boomerang/src/main/java/boomerang/board/dto/BoardBestListRequestDto.java +++ b/boomerang/src/main/java/boomerang/board/dto/BoardBestListRequestDto.java @@ -12,6 +12,7 @@ // @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)은 // JSON 요청 바디에서의 직렬화/역직렬화에만 적용된다. 때문에 직접 필드명을 json 형태로 선언해주었다 public class BoardBestListRequestDto { + @Min(0) private int size = 10; private BoardType board_type; diff --git a/boomerang/src/main/java/boomerang/board/dto/BoardDetailResponseDto.java b/boomerang/src/main/java/boomerang/board/dto/BoardDetailResponseDto.java index f1146a90..9df446c3 100644 --- a/boomerang/src/main/java/boomerang/board/dto/BoardDetailResponseDto.java +++ b/boomerang/src/main/java/boomerang/board/dto/BoardDetailResponseDto.java @@ -8,13 +8,13 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.Getter; - import java.time.LocalDateTime; +import lombok.Getter; @Getter @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class BoardDetailResponseDto { + private Long id; private String title; private String content; @@ -30,7 +30,8 @@ public class BoardDetailResponseDto { // Board 도메인 객체를 받아서 BoardResponseDto를 생성하는 생성자 - public BoardDetailResponseDto(Board board, PageResponseDto commentListResponseDto, boolean isLiked) { + public BoardDetailResponseDto(Board board, + PageResponseDto commentListResponseDto, boolean isLiked) { this.id = board.getId(); this.title = board.getTitle(); this.content = board.getContent(); diff --git a/boomerang/src/main/java/boomerang/board/dto/BoardListRequestDto.java b/boomerang/src/main/java/boomerang/board/dto/BoardListRequestDto.java index 370c8693..2048eb0a 100644 --- a/boomerang/src/main/java/boomerang/board/dto/BoardListRequestDto.java +++ b/boomerang/src/main/java/boomerang/board/dto/BoardListRequestDto.java @@ -14,6 +14,7 @@ // @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)은 // JSON 요청 바디에서의 직렬화/역직렬화에만 적용된다. 때문에 직접 필드명을 json 형태로 선언해주었다 public class BoardListRequestDto { + @Min(0) private int page = 0; @Min(0) diff --git a/boomerang/src/main/java/boomerang/board/dto/BoardRequestDto.java b/boomerang/src/main/java/boomerang/board/dto/BoardRequestDto.java index ed7ca368..e74be36a 100644 --- a/boomerang/src/main/java/boomerang/board/dto/BoardRequestDto.java +++ b/boomerang/src/main/java/boomerang/board/dto/BoardRequestDto.java @@ -8,12 +8,14 @@ @Getter @EqualsAndHashCode public class BoardRequestDto { + private String title; private String content; private BoardType board_type; private Location location; - public BoardRequestDto() {} + public BoardRequestDto() { + } // 생성자 public BoardRequestDto(String title, String content, BoardType board_type, Location location) { diff --git a/boomerang/src/main/java/boomerang/board/dto/BoardResponseDto.java b/boomerang/src/main/java/boomerang/board/dto/BoardResponseDto.java index 850ef373..61da4dd5 100644 --- a/boomerang/src/main/java/boomerang/board/dto/BoardResponseDto.java +++ b/boomerang/src/main/java/boomerang/board/dto/BoardResponseDto.java @@ -8,6 +8,7 @@ @Getter @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class BoardResponseDto { + private Long id; private String title; private String summary; diff --git a/boomerang/src/main/java/boomerang/board/dto/BoardSimpleResponseDto.java b/boomerang/src/main/java/boomerang/board/dto/BoardSimpleResponseDto.java index 1c5066c5..9978599b 100644 --- a/boomerang/src/main/java/boomerang/board/dto/BoardSimpleResponseDto.java +++ b/boomerang/src/main/java/boomerang/board/dto/BoardSimpleResponseDto.java @@ -12,6 +12,7 @@ @Getter @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class BoardSimpleResponseDto { + private Long id; private String title; private String content; diff --git a/boomerang/src/main/java/boomerang/board/repository/BoardRepository.java b/boomerang/src/main/java/boomerang/board/repository/BoardRepository.java index 4075a5eb..ee2d5c9a 100644 --- a/boomerang/src/main/java/boomerang/board/repository/BoardRepository.java +++ b/boomerang/src/main/java/boomerang/board/repository/BoardRepository.java @@ -8,16 +8,13 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import java.time.LocalDate; -import java.time.LocalDateTime; - public interface BoardRepository extends JpaRepository { @Query("SELECT b FROM Board b WHERE b.boardType = :boardType AND " + - "(:searchWord IS NULL OR :searchWord = '' OR b.title LIKE %:searchWord%)") + "(:searchWord IS NULL OR :searchWord = '' OR b.title LIKE %:searchWord%)") Page findByBoardTypeAndTitleContaining(@Param("boardType") BoardType boardType, - @Param("searchWord") String searchWord, - Pageable pageable); + @Param("searchWord") String searchWord, + Pageable pageable); Page findByBoardType(BoardType boardType, Pageable pageable); } \ No newline at end of file diff --git a/boomerang/src/main/java/boomerang/board/scheduler/ScoreScheduler.java b/boomerang/src/main/java/boomerang/board/scheduler/ScoreScheduler.java index 5b79862e..3d61f5f7 100644 --- a/boomerang/src/main/java/boomerang/board/scheduler/ScoreScheduler.java +++ b/boomerang/src/main/java/boomerang/board/scheduler/ScoreScheduler.java @@ -3,11 +3,10 @@ import boomerang.board.domain.Board; import boomerang.board.repository.BoardRepository; import jakarta.transaction.Transactional; +import java.util.List; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import java.util.List; - @Service public class ScoreScheduler { diff --git a/boomerang/src/main/java/boomerang/board/service/BoardService.java b/boomerang/src/main/java/boomerang/board/service/BoardService.java index 95133af9..798d87a9 100644 --- a/boomerang/src/main/java/boomerang/board/service/BoardService.java +++ b/boomerang/src/main/java/boomerang/board/service/BoardService.java @@ -9,20 +9,18 @@ import boomerang.global.exception.BusinessException; import boomerang.global.response.ErrorCode; import boomerang.member.domain.Member; +import java.net.URL; +import java.util.Collections; +import java.util.List; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import java.net.URL; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.Collections; -import java.util.List; - @Service public class BoardService { + private final BoardRepository boardRepository; private final FileService fileService; @@ -35,20 +33,20 @@ public BoardService(BoardRepository boardRepository, FileService fileService) { public Page getBestBoards(BoardBestListRequestDto boardBestListRequestDto) { // 정렬을 score 기준으로 내림차순 설정 PageRequest pageRequest = - PageRequest.of(0, boardBestListRequestDto.getSize(), - Sort.by(Sort.Direction.DESC, "score")); + PageRequest.of(0, boardBestListRequestDto.getSize(), + Sort.by(Sort.Direction.DESC, "score")); - return boardRepository.findByBoardType(boardBestListRequestDto.getBoard_type(), pageRequest); + return boardRepository.findByBoardType(boardBestListRequestDto.getBoard_type(), + pageRequest); } - // 모든 게시물 가져오기 public Page getAllBoards(BoardListRequestDto boardListRequestDto) { PageRequest pageRequest = getPageRequest(boardListRequestDto); return boardRepository.findByBoardTypeAndTitleContaining( - boardListRequestDto.getBoard_type(), boardListRequestDto.getSearch_word(), pageRequest + boardListRequestDto.getBoard_type(), boardListRequestDto.getSearch_word(), pageRequest ); } @@ -58,7 +56,8 @@ public Board getBoard(Long id) { } // 게시물 생성 - public Board createBoard(BoardRequestDto boardRequestDto, Member member, List images) { + public Board createBoard(BoardRequestDto boardRequestDto, Member member, + List images) { // S3에 이미지 업로드 및 URL 리스트 생성 List imageUrls = uploadImages(member, images); @@ -70,7 +69,8 @@ public Board createBoard(BoardRequestDto boardRequestDto, Member member, List images) { + public Board updateBoard(Long id, BoardRequestDto boardRequestDto, Member member, + List images) { // S3에 이미지 업로드 및 URL 리스트 생성 List imageUrls = uploadImages(member, images); @@ -90,7 +90,7 @@ public void deleteBoard(Member member, Long id) { // 게시물 존재 여부 검증 private Board validateBoardExists(Long id) { return boardRepository.findById(id) - .orElseThrow(() -> new BusinessException(ErrorCode.BOARD_NOT_FOUND_ERROR)); + .orElseThrow(() -> new BusinessException(ErrorCode.BOARD_NOT_FOUND_ERROR)); } // 게시물 소유자 검증 @@ -103,9 +103,10 @@ private void validateBoardOwnership(Member member, Long id) { private PageRequest getPageRequest(BoardListRequestDto boardListRequestDto) { return PageRequest.of( - boardListRequestDto.getPage(), - boardListRequestDto.getSize(), - Sort.by(boardListRequestDto.getSort_direction(), boardListRequestDto.getBoard_sort_type().getName()) + boardListRequestDto.getPage(), + boardListRequestDto.getSize(), + Sort.by(boardListRequestDto.getSort_direction(), + boardListRequestDto.getBoard_sort_type().getName()) ); } @@ -137,7 +138,8 @@ private void insertImageUrlsIntoContent(BoardRequestDto boardRequestDto, List 부분을 imageUrls의 URL로 순서대로 대체 for (URL imageUrl : imageUrls) { - content = content.replaceFirst("", ""); + content = content.replaceFirst("", + ""); } boardRequestDto.setContent(content); diff --git a/boomerang/src/main/java/boomerang/chat/controller/ChatRoomController.java b/boomerang/src/main/java/boomerang/chat/controller/ChatRoomController.java index 7994ee9f..8ce55a2b 100644 --- a/boomerang/src/main/java/boomerang/chat/controller/ChatRoomController.java +++ b/boomerang/src/main/java/boomerang/chat/controller/ChatRoomController.java @@ -6,15 +6,19 @@ import boomerang.global.exception.BusinessException; import boomerang.global.response.ErrorResponseDto; import boomerang.global.utils.ResponseHelper; +import java.util.List; 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.ui.Model; -import org.springframework.web.bind.annotation.*; - -import java.util.List; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; @Slf4j @Controller diff --git a/boomerang/src/main/java/boomerang/chat/domain/ChatMessage.java b/boomerang/src/main/java/boomerang/chat/domain/ChatMessage.java index 03fbd728..a8f526ac 100644 --- a/boomerang/src/main/java/boomerang/chat/domain/ChatMessage.java +++ b/boomerang/src/main/java/boomerang/chat/domain/ChatMessage.java @@ -1,16 +1,24 @@ package boomerang.chat.domain; import boomerang.member.domain.Member; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import java.time.LocalDateTime; import lombok.Getter; import org.hibernate.annotations.CreationTimestamp; -import java.time.LocalDateTime; - @Getter @Entity @Table(name = "chat_message") public class ChatMessage { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/boomerang/src/main/java/boomerang/chat/domain/ChatRoom.java b/boomerang/src/main/java/boomerang/chat/domain/ChatRoom.java index 837fb7cd..2133f6a5 100644 --- a/boomerang/src/main/java/boomerang/chat/domain/ChatRoom.java +++ b/boomerang/src/main/java/boomerang/chat/domain/ChatRoom.java @@ -1,17 +1,24 @@ package boomerang.chat.domain; -import jakarta.persistence.*; -import lombok.Getter; -import org.hibernate.annotations.CreationTimestamp; - +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import org.hibernate.annotations.CreationTimestamp; @Getter @Entity @Table(name = "chat_room") public class ChatRoom { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/boomerang/src/main/java/boomerang/chat/dto/ChatMessageListRequestDto.java b/boomerang/src/main/java/boomerang/chat/dto/ChatMessageListRequestDto.java index 63b30dec..d5dc7858 100644 --- a/boomerang/src/main/java/boomerang/chat/dto/ChatMessageListRequestDto.java +++ b/boomerang/src/main/java/boomerang/chat/dto/ChatMessageListRequestDto.java @@ -6,6 +6,7 @@ @Getter public class ChatMessageListRequestDto { + private int page = 0; private int size = 20; private Sort.Direction sortDirection = Sort.Direction.DESC; diff --git a/boomerang/src/main/java/boomerang/chat/dto/ChatMessageListResponseDto.java b/boomerang/src/main/java/boomerang/chat/dto/ChatMessageListResponseDto.java index 19483700..dfb1a8aa 100644 --- a/boomerang/src/main/java/boomerang/chat/dto/ChatMessageListResponseDto.java +++ b/boomerang/src/main/java/boomerang/chat/dto/ChatMessageListResponseDto.java @@ -1,22 +1,22 @@ package boomerang.chat.dto; import boomerang.chat.domain.ChatMessage; -import lombok.Getter; -import org.springframework.data.domain.Page; - import java.util.List; import java.util.stream.Collectors; +import lombok.Getter; +import org.springframework.data.domain.Page; @Getter public class ChatMessageListResponseDto { + private final List messages; private final int currentPage; private final int totalPages; public ChatMessageListResponseDto(Page chatMessagePage) { this.messages = chatMessagePage.stream() - .map(ChatMessageResponseDto::new) - .collect(Collectors.toList()); + .map(ChatMessageResponseDto::new) + .collect(Collectors.toList()); this.currentPage = chatMessagePage.getNumber(); this.totalPages = chatMessagePage.getTotalPages(); } diff --git a/boomerang/src/main/java/boomerang/chat/dto/ChatMessageRequestDto.java b/boomerang/src/main/java/boomerang/chat/dto/ChatMessageRequestDto.java index f557a6d0..6aacfb90 100644 --- a/boomerang/src/main/java/boomerang/chat/dto/ChatMessageRequestDto.java +++ b/boomerang/src/main/java/boomerang/chat/dto/ChatMessageRequestDto.java @@ -4,6 +4,7 @@ @Getter public class ChatMessageRequestDto { + private Long chatRoomId; private String content; } diff --git a/boomerang/src/main/java/boomerang/chat/dto/ChatMessageResponseDto.java b/boomerang/src/main/java/boomerang/chat/dto/ChatMessageResponseDto.java index 62bcd08a..264da710 100644 --- a/boomerang/src/main/java/boomerang/chat/dto/ChatMessageResponseDto.java +++ b/boomerang/src/main/java/boomerang/chat/dto/ChatMessageResponseDto.java @@ -1,12 +1,12 @@ package boomerang.chat.dto; import boomerang.chat.domain.ChatMessage; -import lombok.Getter; - import java.time.LocalDateTime; +import lombok.Getter; @Getter public class ChatMessageResponseDto { + private Long id; private String senderName; private String content; diff --git a/boomerang/src/main/java/boomerang/chat/dto/ChatRoomRequestDto.java b/boomerang/src/main/java/boomerang/chat/dto/ChatRoomRequestDto.java index 646f0467..85adab7e 100644 --- a/boomerang/src/main/java/boomerang/chat/dto/ChatRoomRequestDto.java +++ b/boomerang/src/main/java/boomerang/chat/dto/ChatRoomRequestDto.java @@ -4,5 +4,6 @@ @Getter public class ChatRoomRequestDto { + private String name; } diff --git a/boomerang/src/main/java/boomerang/chat/dto/ChatRoomResponseDto.java b/boomerang/src/main/java/boomerang/chat/dto/ChatRoomResponseDto.java index 2bdd472a..58ff46ca 100644 --- a/boomerang/src/main/java/boomerang/chat/dto/ChatRoomResponseDto.java +++ b/boomerang/src/main/java/boomerang/chat/dto/ChatRoomResponseDto.java @@ -1,12 +1,12 @@ package boomerang.chat.dto; import boomerang.chat.domain.ChatRoom; -import lombok.Getter; - import java.time.LocalDateTime; +import lombok.Getter; @Getter public class ChatRoomResponseDto { + private Long id; private String name; private String creatorName; diff --git a/boomerang/src/main/java/boomerang/chat/repository/ChatMessageRepository.java b/boomerang/src/main/java/boomerang/chat/repository/ChatMessageRepository.java index c479a609..a7035889 100644 --- a/boomerang/src/main/java/boomerang/chat/repository/ChatMessageRepository.java +++ b/boomerang/src/main/java/boomerang/chat/repository/ChatMessageRepository.java @@ -7,5 +7,6 @@ import org.springframework.data.jpa.repository.JpaRepository; public interface ChatMessageRepository extends JpaRepository { + Page findByChatRoom(ChatRoom chatRoom, Pageable pageable); } diff --git a/boomerang/src/main/java/boomerang/chat/repository/ChatRoomRepository.java b/boomerang/src/main/java/boomerang/chat/repository/ChatRoomRepository.java index 8a749bcd..4f1108c8 100644 --- a/boomerang/src/main/java/boomerang/chat/repository/ChatRoomRepository.java +++ b/boomerang/src/main/java/boomerang/chat/repository/ChatRoomRepository.java @@ -4,4 +4,5 @@ import org.springframework.data.jpa.repository.JpaRepository; public interface ChatRoomRepository extends JpaRepository { + } diff --git a/boomerang/src/main/java/boomerang/chat/service/ChatRoomService.java b/boomerang/src/main/java/boomerang/chat/service/ChatRoomService.java index 0fa7639c..f4aad890 100644 --- a/boomerang/src/main/java/boomerang/chat/service/ChatRoomService.java +++ b/boomerang/src/main/java/boomerang/chat/service/ChatRoomService.java @@ -10,15 +10,15 @@ import boomerang.global.exception.BusinessException; import boomerang.global.response.ErrorCode; import boomerang.member.domain.Member; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; -import java.util.List; - @Service @RequiredArgsConstructor public class ChatRoomService { + private final ChatRoomRepository chatRoomRepository; private final ChatMessageRepository chatMessageRepository; @@ -34,9 +34,11 @@ public List getAllChatRooms() { } // 특정 채팅방 메시지 조회 - public Page getChatMessages(Long chatRoomId, ChatMessageListRequestDto chatMessageListRequestDto) { + public Page getChatMessages(Long chatRoomId, + ChatMessageListRequestDto chatMessageListRequestDto) { ChatRoom chatRoom = validateChatRoomExists(chatRoomId); - return chatMessageRepository.findByChatRoom(chatRoom, chatMessageListRequestDto.toPageRequest()); + return chatMessageRepository.findByChatRoom(chatRoom, + chatMessageListRequestDto.toPageRequest()); } // 메시지 전송 @@ -59,6 +61,6 @@ public void deleteChatRoom(String memberEmail, Long roomId) { // 채팅방 존재 여부 확인 private ChatRoom validateChatRoomExists(Long chatRoomId) { return chatRoomRepository.findById(chatRoomId) - .orElseThrow(() -> new BusinessException(ErrorCode.CHATROOM_NOT_FOUND_ERROR)); + .orElseThrow(() -> new BusinessException(ErrorCode.CHATROOM_NOT_FOUND_ERROR)); } } diff --git a/boomerang/src/main/java/boomerang/comment/controller/CommentController.java b/boomerang/src/main/java/boomerang/comment/controller/CommentController.java index 073165ba..a003523d 100644 --- a/boomerang/src/main/java/boomerang/comment/controller/CommentController.java +++ b/boomerang/src/main/java/boomerang/comment/controller/CommentController.java @@ -13,12 +13,19 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.checkerframework.checker.units.qual.C; import org.springframework.data.domain.Page; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; @Slf4j @RestController @@ -30,36 +37,42 @@ public class CommentController { //댓글 조회 @GetMapping("/board/{board_id}/comments") - public ResponseEntity> getAllComment(@PathVariable("board_id") Long boardId, CommentListRequestDto commentListRequestDto) { + public ResponseEntity> getAllComment( + @PathVariable("board_id") Long boardId, CommentListRequestDto commentListRequestDto) { Page commentPage = commentService.getAllComment(boardId, commentListRequestDto); Page commentResponsePage = commentPage.map(CommentResponseDto::new); return ResponseEntity.status(HttpStatus.OK) - .body(new PageResponseDto<>(commentResponsePage)); + .body(new PageResponseDto<>(commentResponsePage)); } //댓글 생성 @PostMapping("/board/{board_id}/comments") - public ResponseEntity createComment(@AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable("board_id") Long boardId, - @Valid @RequestBody CommentRequestDto commentRequestDto) { - Comment comment = commentService.createComment(principalDetails.getMemberEmail(), boardId, commentRequestDto); + public ResponseEntity createComment( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable("board_id") Long boardId, + @Valid @RequestBody CommentRequestDto commentRequestDto) { + Comment comment = commentService.createComment(principalDetails.getMemberEmail(), boardId, + commentRequestDto); return ResponseEntity.status(HttpStatus.OK).body(new CommentResponseDto(comment)); } //댓글 수정 @PutMapping("/board/comments/{comment_id}") - public ResponseEntity updateComment(@AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable("comment_id") Long commentId, - @Valid @RequestBody CommentRequestDto commentRequestDto) { - Comment comment = commentService.updateComment(principalDetails.getMemberEmail(), commentId, commentRequestDto); + public ResponseEntity updateComment( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable("comment_id") Long commentId, + @Valid @RequestBody CommentRequestDto commentRequestDto) { + Comment comment = commentService.updateComment(principalDetails.getMemberEmail(), commentId, + commentRequestDto); return ResponseEntity.status(HttpStatus.OK).body(new CommentResponseDto(comment)); } //댓글 삭제 @DeleteMapping("/board/comments/{comment_id}") - public ResponseEntity deleteComment(@AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable("comment_id") Long commentId) { + public ResponseEntity deleteComment( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable("comment_id") Long commentId) { commentService.deleteComment(principalDetails.getMemberEmail(), commentId); return ResponseEntity.status(HttpStatus.OK).build(); } diff --git a/boomerang/src/main/java/boomerang/comment/domain/Comment.java b/boomerang/src/main/java/boomerang/comment/domain/Comment.java index 9db3b219..3085bde2 100644 --- a/boomerang/src/main/java/boomerang/comment/domain/Comment.java +++ b/boomerang/src/main/java/boomerang/comment/domain/Comment.java @@ -4,7 +4,16 @@ import boomerang.board.domain.Board; import boomerang.comment.dto.CommentRequestDto; import boomerang.member.domain.Member; -import jakarta.persistence.*; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import java.time.LocalDateTime; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -12,8 +21,6 @@ import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import java.time.LocalDateTime; - @Getter @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) diff --git a/boomerang/src/main/java/boomerang/comment/dto/CommentListRequestDto.java b/boomerang/src/main/java/boomerang/comment/dto/CommentListRequestDto.java index 39f9c0d8..7457259c 100644 --- a/boomerang/src/main/java/boomerang/comment/dto/CommentListRequestDto.java +++ b/boomerang/src/main/java/boomerang/comment/dto/CommentListRequestDto.java @@ -12,6 +12,7 @@ @EqualsAndHashCode @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class CommentListRequestDto { + private int page = 0; private int size = 10; private Sort.Direction sortDirection = Sort.Direction.DESC; diff --git a/boomerang/src/main/java/boomerang/comment/dto/CommentRequestDto.java b/boomerang/src/main/java/boomerang/comment/dto/CommentRequestDto.java index b3397c33..e9e078e1 100644 --- a/boomerang/src/main/java/boomerang/comment/dto/CommentRequestDto.java +++ b/boomerang/src/main/java/boomerang/comment/dto/CommentRequestDto.java @@ -17,6 +17,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class CommentRequestDto { + @NotBlank private String text; diff --git a/boomerang/src/main/java/boomerang/comment/dto/CommentResponseDto.java b/boomerang/src/main/java/boomerang/comment/dto/CommentResponseDto.java index 50e551b6..f24ad9e1 100644 --- a/boomerang/src/main/java/boomerang/comment/dto/CommentResponseDto.java +++ b/boomerang/src/main/java/boomerang/comment/dto/CommentResponseDto.java @@ -4,18 +4,18 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; +import java.time.LocalDateTime; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; -import java.time.LocalDateTime; - @Getter @ToString @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class CommentResponseDto { + private Long id; //댓글아이디 private String writerEmail; //작성자이름 private String writerName; @@ -33,7 +33,8 @@ public CommentResponseDto(Comment comment) { this.writerName = comment.getAuthorName(); this.text = comment.getText(); this.isEdited = !comment.getCreatedAt().equals(comment.getUpdatedAt()); // 수정 여부 계산 - this.lastModifiedAt = comment.getUpdatedAt() != null ? comment.getUpdatedAt() : comment.getCreatedAt(); //마지막으로 수정된 시간 제공 + this.lastModifiedAt = comment.getUpdatedAt() != null ? comment.getUpdatedAt() + : comment.getCreatedAt(); //마지막으로 수정된 시간 제공 } } diff --git a/boomerang/src/main/java/boomerang/comment/repository/CommentRepository.java b/boomerang/src/main/java/boomerang/comment/repository/CommentRepository.java index d9bec81f..1a164de1 100644 --- a/boomerang/src/main/java/boomerang/comment/repository/CommentRepository.java +++ b/boomerang/src/main/java/boomerang/comment/repository/CommentRepository.java @@ -1,14 +1,13 @@ package boomerang.comment.repository; import boomerang.comment.domain.Comment; +import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import java.util.Optional; - public interface CommentRepository extends JpaRepository { @Query("SELECT c FROM Comment c WHERE c.board.id = :boardId AND c.isDeleted = 'NOT_DELETED'") diff --git a/boomerang/src/main/java/boomerang/comment/service/CommentService.java b/boomerang/src/main/java/boomerang/comment/service/CommentService.java index 165d62d9..f10b67c9 100644 --- a/boomerang/src/main/java/boomerang/comment/service/CommentService.java +++ b/boomerang/src/main/java/boomerang/comment/service/CommentService.java @@ -66,7 +66,8 @@ public void deleteComment(String email, Long commentId) { //댓글 수정 - public Comment updateComment(String email, Long commentId, CommentRequestDto commentRequestDto) { + public Comment updateComment(String email, Long commentId, + CommentRequestDto commentRequestDto) { Comment comment = getComment(commentId); if (!comment.isMemberCommentAuthor(memberService.getMemberByEmail(email))) { @@ -81,14 +82,14 @@ public Comment updateComment(String email, Long commentId, CommentRequestDto com public Comment getComment(Long commentId) { return commentRepository.findActiveById(commentId) - .orElseThrow(() -> new BusinessException(ErrorCode.COMMENT_NON_EXISTENT)); + .orElseThrow(() -> new BusinessException(ErrorCode.COMMENT_NON_EXISTENT)); } private PageRequest getPageRequest(CommentListRequestDto commentListRequestDto) { return PageRequest.of( - commentListRequestDto.getPage(), - commentListRequestDto.getSize(), - Sort.by(commentListRequestDto.getSortDirection(), commentListRequestDto.getSortBy()) + commentListRequestDto.getPage(), + commentListRequestDto.getSize(), + Sort.by(commentListRequestDto.getSortDirection(), commentListRequestDto.getSortBy()) ); } diff --git a/boomerang/src/main/java/boomerang/comment/util/CommentFilter.java b/boomerang/src/main/java/boomerang/comment/util/CommentFilter.java index 26b95049..39c0a08e 100644 --- a/boomerang/src/main/java/boomerang/comment/util/CommentFilter.java +++ b/boomerang/src/main/java/boomerang/comment/util/CommentFilter.java @@ -6,19 +6,19 @@ import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; import jakarta.annotation.PostConstruct; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.ClassPathResource; -import org.springframework.stereotype.Component; - import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Comparator; import java.util.regex.Pattern; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Component; @Component public class CommentFilter { + //BloomFilter : 속도가 빨라 대규모 데이터 검사에 적절한 자료구조 private BloomFilter profanityFilter; private Pattern profanityPattern; @@ -29,7 +29,7 @@ public class CommentFilter { //전화번호의 정규 표현식 private static final Pattern PHONE_NUMBER_PATTERN = Pattern.compile( - "(\\d{2,4}[-.\\s]?\\d{3,4}[-.\\s]?\\d{4})|" + // 일반 전화번호 형식 + "(\\d{2,4}[-.\\s]?\\d{3,4}[-.\\s]?\\d{4})|" + // 일반 전화번호 형식 "(\\(\\d{2,3}\\)[-\\s]?\\d{3,4}[-\\s]?\\d{4})" // 지역번호가 괄호로 묶인 형식 ); @@ -45,14 +45,15 @@ public void init() { String[] profanities = mapper.readValue(inputStream, String[].class); /* - * 필터링할 데이터의 특징 - * funnel – 구축된 BloomFilter가 사용할 T의 퍼널 (funnel은 입력방식을 지정하는 인터페이스) - * 여기서는 UTF_8 타입의 데이터를 바이트 배열로 변환하여 BloomFilter에 입력할 수 있도록 하는 역할 - * ExpectInsertions – 구축된 BloomFilter에 예상되는 삽입 수 - * fpp - 원하는 거짓양성 확률(양수여야 하고 1.0보다 작아야 함) - */ + * 필터링할 데이터의 특징 + * funnel – 구축된 BloomFilter가 사용할 T의 퍼널 (funnel은 입력방식을 지정하는 인터페이스) + * 여기서는 UTF_8 타입의 데이터를 바이트 배열로 변환하여 BloomFilter에 입력할 수 있도록 하는 역할 + * ExpectInsertions – 구축된 BloomFilter에 예상되는 삽입 수 + * fpp - 원하는 거짓양성 확률(양수여야 하고 1.0보다 작아야 함) + */ - this.profanityFilter = BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), 200, 0.01); + this.profanityFilter = BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), + 200, 0.01); Arrays.sort(profanities, Comparator.comparingInt(String::length).reversed()); @@ -66,7 +67,8 @@ public void init() { throw new BusinessException(ErrorCode.FILE_ERROR); } - this.profanityPattern = Pattern.compile(patternBuilder.substring(0, patternBuilder.length() - 1), Pattern.CASE_INSENSITIVE); + this.profanityPattern = Pattern.compile( + patternBuilder.substring(0, patternBuilder.length() - 1), Pattern.CASE_INSENSITIVE); } private boolean containsProfanity(String input) { @@ -82,9 +84,9 @@ private boolean containsProfanity(String input) { public String filterAndReplaceProfanity(String text) { /* - * [댓글 필터링 방법] - * 1. 속도가 빠른 BloomFilter로 해당 댓글이 욕설을 포함하고 있는지를 검사 - * 2. 포함하고 있을 경우에만 정규 표현식을 이용해 욕설을 ***로 변경 + * [댓글 필터링 방법] + * 1. 속도가 빠른 BloomFilter로 해당 댓글이 욕설을 포함하고 있는지를 검사 + * 2. 포함하고 있을 경우에만 정규 표현식을 이용해 욕설을 ***로 변경 */ if (containsProfanity(text)) { diff --git a/boomerang/src/main/java/boomerang/consultation/controller/ConsultationController.java b/boomerang/src/main/java/boomerang/consultation/controller/ConsultationController.java index 264a4db3..becf16dd 100644 --- a/boomerang/src/main/java/boomerang/consultation/controller/ConsultationController.java +++ b/boomerang/src/main/java/boomerang/consultation/controller/ConsultationController.java @@ -1,6 +1,11 @@ package boomerang.consultation.controller; -import boomerang.consultation.dto.*; +import boomerang.consultation.dto.ConsultationRequestDto; +import boomerang.consultation.dto.ConsultationResponseDto; +import boomerang.consultation.dto.ConsultationResponseListDto; +import boomerang.consultation.dto.ScheduleRequestDto; +import boomerang.consultation.dto.ScheduleResponseDto; +import boomerang.consultation.dto.ScheduleResponseListDto; import boomerang.consultation.service.ConsultationService; import boomerang.global.oauth.dto.PrincipalDetails; import jakarta.validation.Valid; @@ -9,7 +14,14 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor @@ -20,61 +32,78 @@ public class ConsultationController { //상담신청 @PostMapping("/consultation") - public ResponseEntity requestConsultation(@AuthenticationPrincipal PrincipalDetails principalDetails, - @Valid @RequestBody ConsultationRequestDto consultationRequestDto) { - ConsultationResponseDto consultationResponseDto = consultationService.requestConsultation(principalDetails, consultationRequestDto); + public ResponseEntity requestConsultation( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @Valid @RequestBody ConsultationRequestDto consultationRequestDto) { + ConsultationResponseDto consultationResponseDto = consultationService.requestConsultation( + principalDetails, consultationRequestDto); return ResponseEntity.status(HttpStatus.CREATED).body(consultationResponseDto); } //일정등록 @PostMapping("/consultation/schedule") - public ResponseEntity registerSchedule(@AuthenticationPrincipal PrincipalDetails principalDetails, @RequestBody ScheduleRequestDto scheduleRequestDto) { - ScheduleResponseDto scheduleResponseDto = consultationService.registerSchedule(principalDetails, scheduleRequestDto); + public ResponseEntity registerSchedule( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @RequestBody ScheduleRequestDto scheduleRequestDto) { + ScheduleResponseDto scheduleResponseDto = consultationService.registerSchedule( + principalDetails, scheduleRequestDto); return ResponseEntity.status(HttpStatus.CREATED).body(scheduleResponseDto); } //일정 삭제 @DeleteMapping("/consultation/schedule") - public ResponseEntity deleteSchedule(@AuthenticationPrincipal PrincipalDetails principalDetails,@RequestBody ScheduleRequestDto scheduleRequestDto) { + public ResponseEntity deleteSchedule( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @RequestBody ScheduleRequestDto scheduleRequestDto) { consultationService.deleteSchedule(principalDetails, scheduleRequestDto); return ResponseEntity.status(HttpStatus.OK).build(); } //일정 조회 @GetMapping("/consultation/schedule") - public ResponseEntity getSchedule(@AuthenticationPrincipal PrincipalDetails principalDetails){ - ScheduleResponseListDto scheduleResponseListDto = consultationService.getScheduleByMentor(principalDetails); + public ResponseEntity getSchedule( + @AuthenticationPrincipal PrincipalDetails principalDetails) { + ScheduleResponseListDto scheduleResponseListDto = consultationService.getScheduleByMentor( + principalDetails); return ResponseEntity.status(HttpStatus.OK).body(scheduleResponseListDto); } //상담완료 @PutMapping("/consultation/{consultation_id}") - public ResponseEntity requestConsultation(@AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable("consultation_id") Long consultationId) { - ConsultationResponseDto consultationResponseDto = consultationService.completeConsultation(principalDetails, consultationId); + public ResponseEntity requestConsultation( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable("consultation_id") Long consultationId) { + ConsultationResponseDto consultationResponseDto = consultationService.completeConsultation( + principalDetails, consultationId); return ResponseEntity.status(HttpStatus.OK).body(consultationResponseDto); } //상담조회 @GetMapping("/consultation/{consultation_id}") - public ResponseEntity requestConsultation(@PathVariable("consultation_id") Long consultationId) { - ConsultationResponseDto consultationResponseDto = consultationService.getConsultationDetail(consultationId); + public ResponseEntity requestConsultation( + @PathVariable("consultation_id") Long consultationId) { + ConsultationResponseDto consultationResponseDto = consultationService.getConsultationDetail( + consultationId); return ResponseEntity.status(HttpStatus.OK).body(consultationResponseDto); } //멘토별 상담 조회 @GetMapping("mentor/{mentor_id}/consultation") - public ResponseEntity getConsultationOfMentor(@PathVariable("mentor_id") Long mentorId, Pageable pageable) { - ConsultationResponseListDto consultation = consultationService.getConsultationOfMentor(mentorId, pageable); + public ResponseEntity getConsultationOfMentor( + @PathVariable("mentor_id") Long mentorId, Pageable pageable) { + ConsultationResponseListDto consultation = consultationService.getConsultationOfMentor( + mentorId, pageable); return ResponseEntity.status(HttpStatus.OK).body(consultation); } //개인별 상담 내역조회 @GetMapping("member/consultation") - public ResponseEntity getConsultationOfUser(@AuthenticationPrincipal PrincipalDetails principalDetails, Pageable pageable) { - ConsultationResponseListDto consultation = consultationService.getConsultationOfUser(principalDetails, pageable); + public ResponseEntity getConsultationOfUser( + @AuthenticationPrincipal PrincipalDetails principalDetails, Pageable pageable) { + ConsultationResponseListDto consultation = consultationService.getConsultationOfUser( + principalDetails, pageable); return ResponseEntity.status(HttpStatus.OK).body(consultation); } diff --git a/boomerang/src/main/java/boomerang/consultation/domain/Consultation.java b/boomerang/src/main/java/boomerang/consultation/domain/Consultation.java index 5db621c2..68aea39d 100644 --- a/boomerang/src/main/java/boomerang/consultation/domain/Consultation.java +++ b/boomerang/src/main/java/boomerang/consultation/domain/Consultation.java @@ -2,7 +2,17 @@ import boomerang.member.domain.Member; import boomerang.mentor.domain.Mentor; -import jakarta.persistence.*; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import java.time.LocalDate; +import java.time.LocalDateTime; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -10,14 +20,12 @@ import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import java.time.LocalDate; -import java.time.LocalDateTime; - @Getter @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @EntityListeners(AuditingEntityListener.class) public class Consultation { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -49,7 +57,7 @@ public Consultation(Member mentee, Mentor mentor, Schedule schedule) { this.mentee = mentee; this.mentor = mentor; this.schedule = schedule; - this.consultationStatus= ConsultationStatus.PENDING; + this.consultationStatus = ConsultationStatus.PENDING; } public long getMentorId() { diff --git a/boomerang/src/main/java/boomerang/consultation/domain/Schedule.java b/boomerang/src/main/java/boomerang/consultation/domain/Schedule.java index 8ec03ff2..e2437667 100644 --- a/boomerang/src/main/java/boomerang/consultation/domain/Schedule.java +++ b/boomerang/src/main/java/boomerang/consultation/domain/Schedule.java @@ -1,20 +1,29 @@ package boomerang.consultation.domain; import boomerang.mentor.domain.Mentor; -import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; import java.time.LocalDate; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; @Getter @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Schedule { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -23,7 +32,8 @@ public class Schedule { @ElementCollection @Column(length = 24) - private List hourlySlots = new ArrayList<>(Collections.nCopies(24, Boolean.FALSE)); // 하루 24시간 예약 상태를 기본값 false로 초기화된 리스트 + private List hourlySlots = new ArrayList<>( + Collections.nCopies(24, Boolean.FALSE)); // 하루 24시간 예약 상태를 기본값 false로 초기화된 리스트 @ManyToOne @JoinColumn(name = "mentor_id", nullable = false) @@ -54,5 +64,4 @@ public void unreserveSlot(int hour) { } - } diff --git a/boomerang/src/main/java/boomerang/consultation/dto/ConsultationRequestDto.java b/boomerang/src/main/java/boomerang/consultation/dto/ConsultationRequestDto.java index c16d82f2..73269eec 100644 --- a/boomerang/src/main/java/boomerang/consultation/dto/ConsultationRequestDto.java +++ b/boomerang/src/main/java/boomerang/consultation/dto/ConsultationRequestDto.java @@ -12,6 +12,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class ConsultationRequestDto { + @Positive(message = "Mentor ID는 빈값일 수 없습니다.") private long mentorId; int consultationMonth; diff --git a/boomerang/src/main/java/boomerang/consultation/dto/ConsultationResponseDto.java b/boomerang/src/main/java/boomerang/consultation/dto/ConsultationResponseDto.java index f46ee8e3..5ce3d6ac 100644 --- a/boomerang/src/main/java/boomerang/consultation/dto/ConsultationResponseDto.java +++ b/boomerang/src/main/java/boomerang/consultation/dto/ConsultationResponseDto.java @@ -5,16 +5,16 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; +import java.time.LocalDate; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import java.time.LocalDate; - @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class ConsultationResponseDto { + private long consultationId; //상담아이디 private long mentorId; //멘토아이디 private String mentorNickName; //멤토닉네임 diff --git a/boomerang/src/main/java/boomerang/consultation/dto/ConsultationResponseListDto.java b/boomerang/src/main/java/boomerang/consultation/dto/ConsultationResponseListDto.java index 9afef1f1..8c40234b 100644 --- a/boomerang/src/main/java/boomerang/consultation/dto/ConsultationResponseListDto.java +++ b/boomerang/src/main/java/boomerang/consultation/dto/ConsultationResponseListDto.java @@ -3,17 +3,17 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; +import java.util.List; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.domain.Page; -import java.util.List; - @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class ConsultationResponseListDto { + private int totalPage; private int currentPage; private List itemList; diff --git a/boomerang/src/main/java/boomerang/consultation/dto/ScheduleMonthDto.java b/boomerang/src/main/java/boomerang/consultation/dto/ScheduleMonthDto.java index 2d22a22c..45a01638 100644 --- a/boomerang/src/main/java/boomerang/consultation/dto/ScheduleMonthDto.java +++ b/boomerang/src/main/java/boomerang/consultation/dto/ScheduleMonthDto.java @@ -2,17 +2,17 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; +import java.util.List; +import java.util.Map; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.List; -import java.util.Map; - @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class ScheduleMonthDto { + private int month; private List>> dayList; diff --git a/boomerang/src/main/java/boomerang/consultation/dto/ScheduleRequestDto.java b/boomerang/src/main/java/boomerang/consultation/dto/ScheduleRequestDto.java index 3d58abdd..8aba8710 100644 --- a/boomerang/src/main/java/boomerang/consultation/dto/ScheduleRequestDto.java +++ b/boomerang/src/main/java/boomerang/consultation/dto/ScheduleRequestDto.java @@ -2,17 +2,17 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; +import java.util.List; +import java.util.Map; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.List; -import java.util.Map; - @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class ScheduleRequestDto { + private int month; private List>> dayList; diff --git a/boomerang/src/main/java/boomerang/consultation/dto/ScheduleResponseDto.java b/boomerang/src/main/java/boomerang/consultation/dto/ScheduleResponseDto.java index 0f7ea345..0bc48ee1 100644 --- a/boomerang/src/main/java/boomerang/consultation/dto/ScheduleResponseDto.java +++ b/boomerang/src/main/java/boomerang/consultation/dto/ScheduleResponseDto.java @@ -2,18 +2,18 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - import java.util.ArrayList; import java.util.List; import java.util.Map; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class ScheduleResponseDto { + private int month; private List>> dayList = new ArrayList<>(); diff --git a/boomerang/src/main/java/boomerang/consultation/dto/ScheduleResponseListDto.java b/boomerang/src/main/java/boomerang/consultation/dto/ScheduleResponseListDto.java index 5f6e4589..1888c49d 100644 --- a/boomerang/src/main/java/boomerang/consultation/dto/ScheduleResponseListDto.java +++ b/boomerang/src/main/java/boomerang/consultation/dto/ScheduleResponseListDto.java @@ -2,17 +2,17 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; +import java.util.ArrayList; +import java.util.List; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.ArrayList; -import java.util.List; - @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class ScheduleResponseListDto { + private List ScheduleList = new ArrayList<>(); public ScheduleResponseListDto(List scheduleList) { diff --git a/boomerang/src/main/java/boomerang/consultation/repository/ConsultationRepository.java b/boomerang/src/main/java/boomerang/consultation/repository/ConsultationRepository.java index 15c9b98c..8b738519 100644 --- a/boomerang/src/main/java/boomerang/consultation/repository/ConsultationRepository.java +++ b/boomerang/src/main/java/boomerang/consultation/repository/ConsultationRepository.java @@ -8,8 +8,6 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import java.time.LocalDate; - public interface ConsultationRepository extends JpaRepository { Page findAllByMentee(Member mentee, Pageable pageable); diff --git a/boomerang/src/main/java/boomerang/consultation/repository/ScheduleRepository.java b/boomerang/src/main/java/boomerang/consultation/repository/ScheduleRepository.java index 840cc281..d3edb298 100644 --- a/boomerang/src/main/java/boomerang/consultation/repository/ScheduleRepository.java +++ b/boomerang/src/main/java/boomerang/consultation/repository/ScheduleRepository.java @@ -2,14 +2,16 @@ import boomerang.consultation.domain.Schedule; import boomerang.mentor.domain.Mentor; -import org.springframework.data.jpa.repository.JpaRepository; - import java.time.LocalDate; import java.util.List; import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; public interface ScheduleRepository extends JpaRepository { + Optional findByDate(LocalDate date); + Optional findByMentorAndDate(Mentor mentor, LocalDate date); + List findAllByMentor(Mentor mentor); } diff --git a/boomerang/src/main/java/boomerang/consultation/service/ConsultationService.java b/boomerang/src/main/java/boomerang/consultation/service/ConsultationService.java index b9bce8d4..23579075 100644 --- a/boomerang/src/main/java/boomerang/consultation/service/ConsultationService.java +++ b/boomerang/src/main/java/boomerang/consultation/service/ConsultationService.java @@ -1,8 +1,16 @@ package boomerang.consultation.service; -import boomerang.consultation.domain.*; -import boomerang.consultation.dto.*; -import boomerang.consultation.repository.*; +import boomerang.consultation.domain.Consultation; +import boomerang.consultation.domain.Schedule; +import boomerang.consultation.dto.ConsultationRequestDto; +import boomerang.consultation.dto.ConsultationResponseDto; +import boomerang.consultation.dto.ConsultationResponseListDto; +import boomerang.consultation.dto.ScheduleMonthDto; +import boomerang.consultation.dto.ScheduleRequestDto; +import boomerang.consultation.dto.ScheduleResponseDto; +import boomerang.consultation.dto.ScheduleResponseListDto; +import boomerang.consultation.repository.ConsultationRepository; +import boomerang.consultation.repository.ScheduleRepository; import boomerang.global.exception.BusinessException; import boomerang.global.oauth.dto.PrincipalDetails; import boomerang.global.response.ErrorCode; @@ -11,15 +19,18 @@ import boomerang.mentor.domain.Mentor; import boomerang.mentor.service.MentorService; import jakarta.transaction.Transactional; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; -import java.time.LocalDate; -import java.util.*; -import java.util.stream.Collectors; - @Service @RequiredArgsConstructor public class ConsultationService { @@ -29,26 +40,32 @@ public class ConsultationService { private final MemberService memberService; private final MentorService mentorService; - public ConsultationResponseDto requestConsultation(PrincipalDetails principalDetails, ConsultationRequestDto consultationRequestDto) { + public ConsultationResponseDto requestConsultation(PrincipalDetails principalDetails, + ConsultationRequestDto consultationRequestDto) { Member mentee = memberService.getMemberByEmail(principalDetails.getMemberEmail()); Mentor mentor = mentorService.getMentor(consultationRequestDto.getMentorId()); - LocalDate date = LocalDate.of(2024, consultationRequestDto.getConsultationMonth(),consultationRequestDto.getConsultationDay()); - Schedule schedule = scheduleRepository.findByMentorAndDate(mentor,date) - .orElseThrow(() -> new BusinessException(ErrorCode.SCHEDULE_NOT_FOUND_ERROR)); - if (consultationRepository.existsByMenteeAndMentorAndSchedule(mentee, mentor, schedule) && schedule.getHourlySlots().get(consultationRequestDto.getConsultationTime()) == Boolean.FALSE) { - throw new BusinessException(ErrorCode.CONSULTATION_ALREADY_EXISTS); // 이미 신청되어 있는 상담이면 에러 처리 + LocalDate date = LocalDate.of(2024, consultationRequestDto.getConsultationMonth(), + consultationRequestDto.getConsultationDay()); + Schedule schedule = scheduleRepository.findByMentorAndDate(mentor, date) + .orElseThrow(() -> new BusinessException(ErrorCode.SCHEDULE_NOT_FOUND_ERROR)); + if (consultationRepository.existsByMenteeAndMentorAndSchedule(mentee, mentor, schedule) + && schedule.getHourlySlots().get(consultationRequestDto.getConsultationTime()) + == Boolean.FALSE) { + throw new BusinessException( + ErrorCode.CONSULTATION_ALREADY_EXISTS); // 이미 신청되어 있는 상담이면 에러 처리 } - schedule.unreserveSlot(consultationRequestDto.getConsultationTime()); // 상담을 신청되면서 해당 시간대 상태 False로 변경 + schedule.unreserveSlot( + consultationRequestDto.getConsultationTime()); // 상담을 신청되면서 해당 시간대 상태 False로 변경 scheduleRepository.save(schedule); - - - Consultation savedConsultation = consultationRepository.save(new Consultation(mentee, mentor, schedule)); + Consultation savedConsultation = consultationRepository.save( + new Consultation(mentee, mentor, schedule)); return new ConsultationResponseDto(savedConsultation); } - public ConsultationResponseDto completeConsultation(PrincipalDetails principalDetails, Long consultationId) { + public ConsultationResponseDto completeConsultation(PrincipalDetails principalDetails, + Long consultationId) { Member mentee = memberService.getMemberByEmail(principalDetails.getMemberEmail()); Consultation consultation = getConsultation(consultationId); @@ -72,19 +89,22 @@ public ConsultationResponseDto getConsultationDetail(Long consultationId) { } - public ConsultationResponseListDto getConsultationOfUser(PrincipalDetails principalDetails, Pageable pageable) { + public ConsultationResponseListDto getConsultationOfUser(PrincipalDetails principalDetails, + Pageable pageable) { Member member = memberService.getMemberByEmail(principalDetails.getMemberEmail()); - Page consultationResponsePage = consultationRepository.findAllByMentee(member, pageable) - .map(ConsultationResponseDto::new); + Page consultationResponsePage = consultationRepository.findAllByMentee( + member, pageable) + .map(ConsultationResponseDto::new); return new ConsultationResponseListDto(consultationResponsePage); } public ConsultationResponseListDto getConsultationOfMentor(Long mentorId, Pageable pageable) { Mentor mentor = mentorService.getMentor(mentorId); - Page consultationResponsePage = consultationRepository.findAllByMentor(mentor, pageable) - .map(ConsultationResponseDto::new); + Page consultationResponsePage = consultationRepository.findAllByMentor( + mentor, pageable) + .map(ConsultationResponseDto::new); return new ConsultationResponseListDto(consultationResponsePage); @@ -92,31 +112,35 @@ public ConsultationResponseListDto getConsultationOfMentor(Long mentorId, Pageab public Consultation getConsultation(long id) { return consultationRepository.findById(id) - .orElseThrow(() -> new BusinessException(ErrorCode.CONSULTATION_NOT_FOUND_ERROR)); + .orElseThrow(() -> new BusinessException(ErrorCode.CONSULTATION_NOT_FOUND_ERROR)); } @Transactional - public ScheduleResponseDto registerSchedule(PrincipalDetails principalDetails, ScheduleRequestDto scheduleRequestDto) { + public ScheduleResponseDto registerSchedule(PrincipalDetails principalDetails, + ScheduleRequestDto scheduleRequestDto) { Member member = memberService.getMemberByEmail(principalDetails.getMemberEmail()); Mentor mentor = member.getMentor(); if (!mentor.getMember().equals(member)) { throw new BusinessException(ErrorCode.CONSULTATION_NOT_A_MENTOR); } List>> dayList = new ArrayList<>(); - for (Map> dateEntry : scheduleRequestDto.getDayList()){ - for (Map.Entry> entry : dateEntry.entrySet()){ - LocalDate date = LocalDate.of(2024, scheduleRequestDto.getMonth(),Integer.parseInt(entry.getKey())); // DTO의 월, 일로 LocalDate 생성 + for (Map> dateEntry : scheduleRequestDto.getDayList()) { + for (Map.Entry> entry : dateEntry.entrySet()) { + LocalDate date = LocalDate.of(2024, scheduleRequestDto.getMonth(), + Integer.parseInt(entry.getKey())); // DTO의 월, 일로 LocalDate 생성 Schedule schedule = scheduleRepository.findByMentorAndDate(mentor, date) - .orElse(new Schedule(mentor,date)); // 해당 날짜의 Schedule이 없으면 새로 생성 + .orElse(new Schedule(mentor, date)); // 해당 날짜의 Schedule이 없으면 새로 생성 List hours = entry.getValue(); List reservedHours = new ArrayList<>(); for (int hour : hours) { if (hour < 0 || hour >= 24) { - throw new BusinessException(ErrorCode.CONSULTATION_TIME_REQUEST_ERROR); // 0 ~ 23 범위에 벗어나는 시간 예외 처리 + throw new BusinessException( + ErrorCode.CONSULTATION_TIME_REQUEST_ERROR); // 0 ~ 23 범위에 벗어나는 시간 예외 처리 } if (schedule.getHourlySlots().get(hour)) { - throw new BusinessException(ErrorCode.CONSULTATION_ALREADY_EXISTS); // 중복된 시간 예외 처리 + throw new BusinessException( + ErrorCode.CONSULTATION_ALREADY_EXISTS); // 중복된 시간 예외 처리 } schedule.reserveSlot(hour); // 시간대 예약 reservedHours.add(hour); @@ -131,17 +155,19 @@ public ScheduleResponseDto registerSchedule(PrincipalDetails principalDetails, S } @Transactional - public void deleteSchedule(PrincipalDetails principalDetails, ScheduleRequestDto scheduleRequestDto) { + public void deleteSchedule(PrincipalDetails principalDetails, + ScheduleRequestDto scheduleRequestDto) { Member member = memberService.getMemberByEmail(principalDetails.getMemberEmail()); Mentor mentor = member.getMentor(); if (!mentor.getMember().equals(member)) { throw new BusinessException(ErrorCode.CONSULTATION_NOT_A_MENTOR); } - for (Map> dateEntry : scheduleRequestDto.getDayList()){ - for (Map.Entry> entry : dateEntry.entrySet()){ - LocalDate date = LocalDate.of(2024, scheduleRequestDto.getMonth(),Integer.parseInt(entry.getKey())); + for (Map> dateEntry : scheduleRequestDto.getDayList()) { + for (Map.Entry> entry : dateEntry.entrySet()) { + LocalDate date = LocalDate.of(2024, scheduleRequestDto.getMonth(), + Integer.parseInt(entry.getKey())); Schedule schedule = scheduleRepository.findByMentorAndDate(mentor, date) - .orElseThrow(() -> new BusinessException(ErrorCode.SCHEDULE_NOT_FOUND_ERROR)); + .orElseThrow(() -> new BusinessException(ErrorCode.SCHEDULE_NOT_FOUND_ERROR)); List hours = entry.getValue(); for (int hour : hours) { if (hour < 0 || hour >= 24) { @@ -154,10 +180,10 @@ public void deleteSchedule(PrincipalDetails principalDetails, ScheduleRequestDto } } - public ScheduleResponseListDto getScheduleByMentor(PrincipalDetails principalDetails){ + public ScheduleResponseListDto getScheduleByMentor(PrincipalDetails principalDetails) { Member member = memberService.getMemberByEmail(principalDetails.getMemberEmail()); Mentor mentor = member.getMentor(); - if (member.getMentor() == null){ + if (member.getMentor() == null) { throw new BusinessException(ErrorCode.CONSULTATION_NOT_A_MENTOR); } List scheduleList = scheduleRepository.findAllByMentor(mentor); @@ -182,13 +208,13 @@ public ScheduleResponseListDto getScheduleByMentor(PrincipalDetails principalDet // 해당 월이 이미 존재하면 해당 일 데이터 추가, 없으면 새로 생성 monthToDaysMap.computeIfAbsent(month, k -> new ArrayList<>()) - .add(Collections.singletonMap(day, reservedHours)); + .add(Collections.singletonMap(day, reservedHours)); } // Map을 ScheduleMonthDto 리스트로 변환 List scheduleMonthDtoList = monthToDaysMap.entrySet().stream() - .map(entry -> new ScheduleMonthDto(entry.getKey(), entry.getValue())) - .collect(Collectors.toList()); + .map(entry -> new ScheduleMonthDto(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()); return new ScheduleResponseListDto(scheduleMonthDtoList); } diff --git a/boomerang/src/main/java/boomerang/documents/controller/DocumentController.java b/boomerang/src/main/java/boomerang/documents/controller/DocumentController.java index ff3aa38c..0f951883 100644 --- a/boomerang/src/main/java/boomerang/documents/controller/DocumentController.java +++ b/boomerang/src/main/java/boomerang/documents/controller/DocumentController.java @@ -23,7 +23,8 @@ public class DocumentController { private final DocumentService documentService; @PostMapping - public ResponseEntity generateDocument(@RequestBody DocumentRequestDto requestDto) { + public ResponseEntity generateDocument( + @RequestBody DocumentRequestDto requestDto) { try { DocumentResponseDto responseDto = documentService.generateDocument(requestDto); @@ -31,7 +32,8 @@ public ResponseEntity generateDocument(@RequestBody DocumentR return ResponseEntity.ok() .contentType(MediaType.APPLICATION_PDF) - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + responseDto.getFileName() + "\"") + .header(HttpHeaders.CONTENT_DISPOSITION, + "attachment; filename=\"" + responseDto.getFileName() + "\"") .body(resource); } catch (Exception e) { diff --git a/boomerang/src/main/java/boomerang/documents/dto/DocumentRequestDto.java b/boomerang/src/main/java/boomerang/documents/dto/DocumentRequestDto.java index e5c9e516..630fb5fc 100644 --- a/boomerang/src/main/java/boomerang/documents/dto/DocumentRequestDto.java +++ b/boomerang/src/main/java/boomerang/documents/dto/DocumentRequestDto.java @@ -5,11 +5,11 @@ import boomerang.progress.domain.SubStepEnum; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.Map; @Getter @NoArgsConstructor diff --git a/boomerang/src/main/java/boomerang/documents/dto/DocumentResponseDto.java b/boomerang/src/main/java/boomerang/documents/dto/DocumentResponseDto.java index 85e6dc33..653e8f18 100644 --- a/boomerang/src/main/java/boomerang/documents/dto/DocumentResponseDto.java +++ b/boomerang/src/main/java/boomerang/documents/dto/DocumentResponseDto.java @@ -1,11 +1,12 @@ package boomerang.documents.dto; -import lombok.Getter; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import lombok.Getter; @Getter public class DocumentResponseDto { + private final byte[] content; private final String fileName; diff --git a/boomerang/src/main/java/boomerang/documents/service/DocumentService.java b/boomerang/src/main/java/boomerang/documents/service/DocumentService.java index f6d49b36..01991229 100644 --- a/boomerang/src/main/java/boomerang/documents/service/DocumentService.java +++ b/boomerang/src/main/java/boomerang/documents/service/DocumentService.java @@ -4,13 +4,12 @@ import boomerang.documents.dto.DocumentResponseDto; import boomerang.global.exception.BusinessException; import boomerang.global.response.ErrorCode; +import boomerang.progress.service.SubStepInfoService; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.util.Map; import java.util.Optional; - -import boomerang.progress.service.SubStepInfoService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.pdfbox.Loader; diff --git a/boomerang/src/main/java/boomerang/email/dto/EmailVerificationResponseDto.java b/boomerang/src/main/java/boomerang/email/dto/EmailVerificationResponseDto.java index 07b39ab4..4e3cd1a8 100644 --- a/boomerang/src/main/java/boomerang/email/dto/EmailVerificationResponseDto.java +++ b/boomerang/src/main/java/boomerang/email/dto/EmailVerificationResponseDto.java @@ -6,6 +6,7 @@ @Getter @AllArgsConstructor public class EmailVerificationResponseDto { + private String email; private String message; } \ No newline at end of file diff --git a/boomerang/src/main/java/boomerang/email/validation/EmailDomain.java b/boomerang/src/main/java/boomerang/email/validation/EmailDomain.java index d4795d99..9ce0adaf 100644 --- a/boomerang/src/main/java/boomerang/email/validation/EmailDomain.java +++ b/boomerang/src/main/java/boomerang/email/validation/EmailDomain.java @@ -13,7 +13,10 @@ @Constraint(validatedBy = EmailDomainValidator.class) @Documented public @interface EmailDomain { + String message() default "허용되지 않는 이메일 도메인입니다"; + Class[] groups() default {}; + Class[] payload() default {}; } \ No newline at end of file diff --git a/boomerang/src/main/java/boomerang/email/validation/EmailDomainValidator.java b/boomerang/src/main/java/boomerang/email/validation/EmailDomainValidator.java index 7962b30e..c47e987c 100644 --- a/boomerang/src/main/java/boomerang/email/validation/EmailDomainValidator.java +++ b/boomerang/src/main/java/boomerang/email/validation/EmailDomainValidator.java @@ -6,6 +6,7 @@ import java.util.List; public class EmailDomainValidator implements ConstraintValidator { + private static final List ALLOWED_DOMAINS = Arrays.asList( "pusan.ac.kr", "naver.com" diff --git a/boomerang/src/main/java/boomerang/file/config/AmazonS3Config.java b/boomerang/src/main/java/boomerang/file/config/AmazonS3Config.java index cb3d1005..a8f45b5d 100644 --- a/boomerang/src/main/java/boomerang/file/config/AmazonS3Config.java +++ b/boomerang/src/main/java/boomerang/file/config/AmazonS3Config.java @@ -9,6 +9,7 @@ @Configuration public class AmazonS3Config { + @Value("${cloud.aws.credentials.access-key}") private String accessKey; @@ -21,9 +22,9 @@ public class AmazonS3Config { @Bean public S3Client s3Client() { return S3Client.builder() - .credentialsProvider(this::awsCredentials) - .region(Region.of(region)) - .build(); + .credentialsProvider(this::awsCredentials) + .region(Region.of(region)) + .build(); } private AwsCredentials awsCredentials() { diff --git a/boomerang/src/main/java/boomerang/file/controller/FileController.java b/boomerang/src/main/java/boomerang/file/controller/FileController.java index 60757114..d5019774 100644 --- a/boomerang/src/main/java/boomerang/file/controller/FileController.java +++ b/boomerang/src/main/java/boomerang/file/controller/FileController.java @@ -3,6 +3,7 @@ import boomerang.file.dto.FileResponseDto; import boomerang.file.service.FileService; import boomerang.global.oauth.dto.PrincipalDetails; +import java.net.URL; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; @@ -12,12 +13,11 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import java.net.URL; - @RestController @RequestMapping("/api/v1/files") public class FileController { + private final FileService fileService; public FileController(FileService fileService) { @@ -26,10 +26,10 @@ public FileController(FileService fileService) { @PostMapping(value = "/upload", consumes = "multipart/form-data") public ResponseEntity upload( - @AuthenticationPrincipal PrincipalDetails principalDetails, - @RequestParam("file") MultipartFile multipartFile) { + @AuthenticationPrincipal PrincipalDetails principalDetails, + @RequestParam("file") MultipartFile multipartFile) { URL fileUrl = fileService.upload(principalDetails.getMemberEmail(), multipartFile); return ResponseEntity.status(HttpStatus.OK) - .body(new FileResponseDto(fileUrl)); + .body(new FileResponseDto(fileUrl)); } } diff --git a/boomerang/src/main/java/boomerang/file/dto/FileResponseDto.java b/boomerang/src/main/java/boomerang/file/dto/FileResponseDto.java index 7b9290ad..b348a57e 100644 --- a/boomerang/src/main/java/boomerang/file/dto/FileResponseDto.java +++ b/boomerang/src/main/java/boomerang/file/dto/FileResponseDto.java @@ -2,13 +2,13 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.Getter; - import java.net.URL; +import lombok.Getter; @Getter @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class FileResponseDto { + private URL fileUrl; public FileResponseDto(URL fileUrl) { diff --git a/boomerang/src/main/java/boomerang/file/service/AmazonS3Service.java b/boomerang/src/main/java/boomerang/file/service/AmazonS3Service.java index ad64f203..74d3f985 100644 --- a/boomerang/src/main/java/boomerang/file/service/AmazonS3Service.java +++ b/boomerang/src/main/java/boomerang/file/service/AmazonS3Service.java @@ -2,6 +2,9 @@ import boomerang.global.exception.BusinessException; import boomerang.global.response.ErrorCode; +import java.net.URL; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -10,10 +13,6 @@ import software.amazon.awssdk.services.s3.model.GetUrlRequest; import software.amazon.awssdk.services.s3.model.PutObjectRequest; -import java.net.URL; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; - @Service public class AmazonS3Service implements FileService { @@ -29,7 +28,7 @@ public AmazonS3Service(S3Client amazonS3Client) { @Override public URL upload(String email, MultipartFile multipartFile) { String fileName = String.join("/", email, - LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss.SSSSSS"))); + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss.SSSSSS"))); return putImage(fileName, multipartFile); } @@ -39,19 +38,19 @@ public URL putImage(String fileName, MultipartFile multipartFile) { // 업로드할 파일 정보 설정 PutObjectRequest putObjectRequest = PutObjectRequest.builder() - .bucket(bucket) - .contentLength(multipartFile.getSize()) - .contentType(multipartFile.getContentType()) - .key(fileName) - .build(); + .bucket(bucket) + .contentLength(multipartFile.getSize()) + .contentType(multipartFile.getContentType()) + .key(fileName) + .build(); RequestBody requestBody = RequestBody.fromBytes(multipartFile.getBytes()); amazonS3Client.putObject(putObjectRequest, requestBody); GetUrlRequest getUrlRequest = GetUrlRequest.builder() - .bucket(bucket) - .key(fileName) - .build(); + .bucket(bucket) + .key(fileName) + .build(); return amazonS3Client.utilities().getUrl(getUrlRequest); diff --git a/boomerang/src/main/java/boomerang/file/service/FileService.java b/boomerang/src/main/java/boomerang/file/service/FileService.java index 2a30f8fb..4fdadfb2 100644 --- a/boomerang/src/main/java/boomerang/file/service/FileService.java +++ b/boomerang/src/main/java/boomerang/file/service/FileService.java @@ -1,11 +1,11 @@ package boomerang.file.service; +import java.net.URL; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import java.net.URL; - @Service public interface FileService { + URL upload(String email, MultipartFile multipartFile); } diff --git a/boomerang/src/main/java/boomerang/global/MyCrudRepository.java b/boomerang/src/main/java/boomerang/global/MyCrudRepository.java index a2afb7d7..c91b294b 100644 --- a/boomerang/src/main/java/boomerang/global/MyCrudRepository.java +++ b/boomerang/src/main/java/boomerang/global/MyCrudRepository.java @@ -1,13 +1,13 @@ package boomerang.global; -import org.springframework.data.repository.NoRepositoryBean; -import org.springframework.data.repository.Repository; - import java.util.List; import java.util.Optional; +import org.springframework.data.repository.NoRepositoryBean; +import org.springframework.data.repository.Repository; @NoRepositoryBean public interface MyCrudRepository extends Repository { + List findAll(); T save(T entity); diff --git a/boomerang/src/main/java/boomerang/global/config/RedisConfig.java b/boomerang/src/main/java/boomerang/global/config/RedisConfig.java index abd4058d..93232ad5 100644 --- a/boomerang/src/main/java/boomerang/global/config/RedisConfig.java +++ b/boomerang/src/main/java/boomerang/global/config/RedisConfig.java @@ -11,9 +11,6 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; -import io.lettuce.core.ClientOptions; -import io.lettuce.core.protocol.ProtocolVersion; - @Configuration public class RedisConfig { diff --git a/boomerang/src/main/java/boomerang/global/config/SecurityConfig.java b/boomerang/src/main/java/boomerang/global/config/SecurityConfig.java index 423b5b1d..6ce60698 100644 --- a/boomerang/src/main/java/boomerang/global/config/SecurityConfig.java +++ b/boomerang/src/main/java/boomerang/global/config/SecurityConfig.java @@ -6,6 +6,8 @@ import boomerang.global.utils.JwtFilter; import boomerang.global.utils.JwtUtil; import jakarta.servlet.http.HttpServletRequest; +import java.util.Arrays; +import java.util.Collections; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -21,9 +23,6 @@ import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import java.util.Arrays; -import java.util.Collections; - @Configuration @EnableWebSecurity //createdAt과 updatedAt 필드를 자동으로 관리하기 위해 추가하는 코드 @@ -42,7 +41,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { //cors 설정 http - .cors(corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() { + .cors( + corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() { @Override public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { @@ -50,11 +50,16 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { CorsConfiguration configuration = new CorsConfiguration(); // 8080 추가 - configuration.setAllowedOrigins(Arrays.asList("http://localhost:5173", "http://localhost:8080")); //3000 허용 - configuration.setAllowedMethods(Collections.singletonList("*")); //모든 HTTP 메서드 허용 - configuration.setAllowCredentials(true); //쿠키 사용 - configuration.setAllowedHeaders(Collections.singletonList("*")); //클라이언트는 모든 타입의 헤더를 사용 - configuration.setMaxAge(3600L); //프리플라이트 요청 결과 한시간동안 유효 + configuration.setAllowedOrigins(Arrays.asList("http://localhost:5173", + "http://localhost:8080")); //3000 허용 + configuration.setAllowedMethods(Collections.singletonList( + "*")); //모든 HTTP 메서드 허용 + configuration.setAllowCredentials( + true); //쿠키 사용 + configuration.setAllowedHeaders(Collections.singletonList( + "*")); //클라이언트는 모든 타입의 헤더를 사용 + configuration.setMaxAge( + 3600L); //프리플라이트 요청 결과 한시간동안 유효 //클라이언트가 응답에서 Set-Cookie, Authorization의 헤더에 접근할 수 있도록 허용 configuration.setExposedHeaders(Collections.singletonList("Set-Cookie")); @@ -66,47 +71,52 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { //csrf disable http - .csrf((auth) -> auth.disable()); + .csrf((auth) -> auth.disable()); //From 로그인 방식 disable http - .formLogin((auth) -> auth.disable()); + .formLogin((auth) -> auth.disable()); //HTTP Basic 인증 방식 disable http - .httpBasic((auth) -> auth.disable()); + .httpBasic((auth) -> auth.disable()); // H2 콘솔을 사용하기 위해 프레임 옵션 비활성화 http - .headers((headersConfigurer) -> headersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)); - + .headers((headersConfigurer) -> headersConfigurer.frameOptions( + HeadersConfigurer.FrameOptionsConfig::sameOrigin)); //JWTFilter 추가 (이후 JWT 필터 구현 후 추가) http - .addFilterBefore(new JwtFilter(jwtUtil, principalService, clientServerProperties), UsernamePasswordAuthenticationFilter.class) - .exceptionHandling(handeler -> handeler.authenticationEntryPoint(new SecurityAuthenticationEntryPoint())); + .addFilterBefore(new JwtFilter(jwtUtil, principalService, clientServerProperties), + UsernamePasswordAuthenticationFilter.class) + .exceptionHandling(handeler -> handeler.authenticationEntryPoint( + new SecurityAuthenticationEntryPoint())); //경로별 인가 작업 http - .authorizeHttpRequests((auth) -> auth - .requestMatchers("/api/v1/member/nickname","/api/v1/board/comments/**", "/api/v1/progress/**").authenticated() - .requestMatchers(HttpMethod.GET, "/api/v1/member").authenticated() - .requestMatchers(HttpMethod.POST, "/api/v1/board", "/api/v1/board/*/comments", "/api/v1/board/*/likes").authenticated() // POST 요청 추가 - .requestMatchers(HttpMethod.PUT, "/api/v1/board/*", "/api/v1/board/*/comments/*").authenticated() // POST 요청 추가 - .requestMatchers(HttpMethod.DELETE, "/api/v1/board/*", "/api/v1/board/*/comments/*", "/api/v1/board/*/likes").authenticated() // DELETE 요청 추가 - .requestMatchers("/api/v1/chat/**").permitAll() // 채팅 경로 모두 허용 - .anyRequest().permitAll()); - + .authorizeHttpRequests((auth) -> auth + .requestMatchers("/api/v1/member/nickname", "/api/v1/board/comments/**", + "/api/v1/progress/**").authenticated() + .requestMatchers(HttpMethod.GET, "/api/v1/member").authenticated() + .requestMatchers(HttpMethod.POST, "/api/v1/board", "/api/v1/board/*/comments", + "/api/v1/board/*/likes").authenticated() // POST 요청 추가 + .requestMatchers(HttpMethod.PUT, "/api/v1/board/*", "/api/v1/board/*/comments/*", + "/api/v1/member/*").authenticated() // POST 요청 추가 + .requestMatchers(HttpMethod.DELETE, "/api/v1/board/*", "/api/v1/board/*/comments/*", + "/api/v1/board/*/likes").authenticated() // DELETE 요청 추가 + .requestMatchers("/api/v1/chat/**").permitAll() // 채팅 경로 모두 허용 + .anyRequest().permitAll()); //세션 설정 : STATELESS http - .sessionManagement((session) -> session - .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); + .sessionManagement((session) -> session + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); // H2 콘솔을 사용하기 위해 프레임 옵션 비활성화 http - .headers((headersConfigurer) -> headersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)); - + .headers((headersConfigurer) -> headersConfigurer.frameOptions( + HeadersConfigurer.FrameOptionsConfig::sameOrigin)); return http.build(); } diff --git a/boomerang/src/main/java/boomerang/global/config/WebConfig.java b/boomerang/src/main/java/boomerang/global/config/WebConfig.java index 007f05a3..00faaaa6 100644 --- a/boomerang/src/main/java/boomerang/global/config/WebConfig.java +++ b/boomerang/src/main/java/boomerang/global/config/WebConfig.java @@ -19,11 +19,12 @@ public void addFormatters(FormatterRegistry registry) { @Override public void addCorsMappings(CorsRegistry corsRegistry) { corsRegistry.addMapping("/**") - // 8080 추가 - .allowedOrigins("http://localhost:5173", "http://localhost:8080", "http://54.252.224.76:80", "http://54.252.224.76") - .allowedMethods("GET", "POST", "PUT", "DELETE") - .allowedHeaders("*") - .allowCredentials(true) - .exposedHeaders("Set-Cookie", "Authorization"); // Authorization 헤더 추가 + // 8080 추가 + .allowedOrigins("http://localhost:5173", "http://localhost:8080", + "http://54.252.224.76:80", "http://54.252.224.76") + .allowedMethods("GET", "POST", "PUT", "DELETE") + .allowedHeaders("*") + .allowCredentials(true) + .exposedHeaders("Set-Cookie", "Authorization"); // Authorization 헤더 추가 } } diff --git a/boomerang/src/main/java/boomerang/global/config/WebSocketConfig.java b/boomerang/src/main/java/boomerang/global/config/WebSocketConfig.java index c017c448..f4294a96 100644 --- a/boomerang/src/main/java/boomerang/global/config/WebSocketConfig.java +++ b/boomerang/src/main/java/boomerang/global/config/WebSocketConfig.java @@ -9,6 +9,7 @@ @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { + @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new ChatWebSocketHandler(), "/ws/chat/{roomId}").setAllowedOrigins("*"); diff --git a/boomerang/src/main/java/boomerang/global/exception/AccessTokenNotExistsException.java b/boomerang/src/main/java/boomerang/global/exception/AccessTokenNotExistsException.java index 7f018ac4..3a397740 100644 --- a/boomerang/src/main/java/boomerang/global/exception/AccessTokenNotExistsException.java +++ b/boomerang/src/main/java/boomerang/global/exception/AccessTokenNotExistsException.java @@ -3,6 +3,7 @@ import boomerang.global.response.ErrorCode; public class AccessTokenNotExistsException extends BusinessException { + public AccessTokenNotExistsException() { super(ErrorCode.ACCESS_TOKEN_NOT_EXISTS_ERROR); } diff --git a/boomerang/src/main/java/boomerang/global/exception/BusinessException.java b/boomerang/src/main/java/boomerang/global/exception/BusinessException.java index 839f0328..0e24d371 100644 --- a/boomerang/src/main/java/boomerang/global/exception/BusinessException.java +++ b/boomerang/src/main/java/boomerang/global/exception/BusinessException.java @@ -1,10 +1,10 @@ package boomerang.global.exception; import boomerang.global.response.ErrorCode; - import java.util.Arrays; public class BusinessException extends RuntimeException { + private final ErrorCode errorCode; public BusinessException(ErrorCode errorCode) { diff --git a/boomerang/src/main/java/boomerang/global/exception/DomainValidationException.java b/boomerang/src/main/java/boomerang/global/exception/DomainValidationException.java index 781cd489..06fd5340 100644 --- a/boomerang/src/main/java/boomerang/global/exception/DomainValidationException.java +++ b/boomerang/src/main/java/boomerang/global/exception/DomainValidationException.java @@ -2,12 +2,12 @@ import boomerang.global.response.ErrorCode; - import java.util.Arrays; // Embedded 한 값의 Exception // public class DomainValidationException extends RuntimeException { + private final ErrorCode errorCode; public DomainValidationException(ErrorCode errorCode) { diff --git a/boomerang/src/main/java/boomerang/global/exception/KakaoException.java b/boomerang/src/main/java/boomerang/global/exception/KakaoException.java index a0ba7c06..6472d2ff 100644 --- a/boomerang/src/main/java/boomerang/global/exception/KakaoException.java +++ b/boomerang/src/main/java/boomerang/global/exception/KakaoException.java @@ -1,11 +1,11 @@ package boomerang.global.exception; +import java.util.Arrays; import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; -import java.util.Arrays; - public class KakaoException extends RuntimeException { + private final HttpStatus status; private final String message; diff --git a/boomerang/src/main/java/boomerang/global/handler/ChatWebSocketHandler.java b/boomerang/src/main/java/boomerang/global/handler/ChatWebSocketHandler.java index 767bcb7d..078dae9f 100644 --- a/boomerang/src/main/java/boomerang/global/handler/ChatWebSocketHandler.java +++ b/boomerang/src/main/java/boomerang/global/handler/ChatWebSocketHandler.java @@ -1,12 +1,11 @@ package boomerang.global.handler; +import java.util.HashSet; +import java.util.Set; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; -import java.util.HashSet; -import java.util.Set; - public class ChatWebSocketHandler extends TextWebSocketHandler { private final Set sessions = new HashSet<>(); @@ -24,7 +23,8 @@ public void handleTextMessage(WebSocketSession session, TextMessage message) thr } @Override - public void afterConnectionClosed(WebSocketSession session, org.springframework.web.socket.CloseStatus status) throws Exception { + public void afterConnectionClosed(WebSocketSession session, + org.springframework.web.socket.CloseStatus status) throws Exception { sessions.remove(session); } } diff --git a/boomerang/src/main/java/boomerang/global/handler/GlobalExceptionHandler.java b/boomerang/src/main/java/boomerang/global/handler/GlobalExceptionHandler.java index 4f3f1a6e..4a7a8c0b 100644 --- a/boomerang/src/main/java/boomerang/global/handler/GlobalExceptionHandler.java +++ b/boomerang/src/main/java/boomerang/global/handler/GlobalExceptionHandler.java @@ -90,7 +90,7 @@ public ResponseEntity handleException(IllegalStateException e) return ResponseHelper.createErrorResponse(errorCode, e.getMessage()); } - + @Order(2) @ExceptionHandler(KakaoException.class) public ResponseEntity handleException(KakaoException e) { diff --git a/boomerang/src/main/java/boomerang/global/handler/SecurityAuthenticationEntryPoint.java b/boomerang/src/main/java/boomerang/global/handler/SecurityAuthenticationEntryPoint.java index 0af06403..f9902dc7 100644 --- a/boomerang/src/main/java/boomerang/global/handler/SecurityAuthenticationEntryPoint.java +++ b/boomerang/src/main/java/boomerang/global/handler/SecurityAuthenticationEntryPoint.java @@ -6,23 +6,22 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; -import java.io.IOException; - public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint { private final ObjectMapper objectMapper = new ObjectMapper(); // ObjectMapper 생성 @Override - public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { + public void commence(HttpServletRequest request, HttpServletResponse response, + AuthenticationException authException) throws IOException, ServletException { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401 Unauthorized response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); - // ErrorResponseDto를 JSON으로 변환 ErrorResponseDto errorResponseDto = new ErrorResponseDto(ErrorCode.LOGIN_REQUIRED); String jsonResponse = objectMapper.writeValueAsString(errorResponseDto); diff --git a/boomerang/src/main/java/boomerang/global/oauth/dto/PrincipalDetails.java b/boomerang/src/main/java/boomerang/global/oauth/dto/PrincipalDetails.java index 642eb2aa..cc59de54 100644 --- a/boomerang/src/main/java/boomerang/global/oauth/dto/PrincipalDetails.java +++ b/boomerang/src/main/java/boomerang/global/oauth/dto/PrincipalDetails.java @@ -2,15 +2,15 @@ import boomerang.member.domain.Member; import boomerang.member.domain.MemberRole; +import java.util.ArrayList; +import java.util.Collection; import lombok.Getter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; -import java.util.ArrayList; -import java.util.Collection; - @Getter public class PrincipalDetails implements UserDetails { + private Member member; public PrincipalDetails(Member member) { diff --git a/boomerang/src/main/java/boomerang/global/oauth/service/PrincipalService.java b/boomerang/src/main/java/boomerang/global/oauth/service/PrincipalService.java index 91cb20a3..e942b2c6 100644 --- a/boomerang/src/main/java/boomerang/global/oauth/service/PrincipalService.java +++ b/boomerang/src/main/java/boomerang/global/oauth/service/PrincipalService.java @@ -25,7 +25,7 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx public UserDetails loadUserByEmail(String email) throws UsernameNotFoundException { Member member = memberRepository.findByEmail(email) - .orElseThrow(MemberNotFoundException::new); + .orElseThrow(MemberNotFoundException::new); return new PrincipalDetails(member); } // 필수 메서드 구현 (UserDetailsService 인터페이스의 메서드) diff --git a/boomerang/src/main/java/boomerang/global/properties/ClientServerProperties.java b/boomerang/src/main/java/boomerang/global/properties/ClientServerProperties.java index 74cfd34f..03473ec2 100644 --- a/boomerang/src/main/java/boomerang/global/properties/ClientServerProperties.java +++ b/boomerang/src/main/java/boomerang/global/properties/ClientServerProperties.java @@ -1,14 +1,15 @@ package boomerang.global.properties; import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import org.springframework.beans.factory.annotation.Value; @Getter @Component @ConfigurationProperties(prefix = "client.server") public class ClientServerProperties { + @Value("${client.server.home}") private String home; diff --git a/boomerang/src/main/java/boomerang/global/response/ErrorCode.java b/boomerang/src/main/java/boomerang/global/response/ErrorCode.java index 02f99d91..a352e18b 100644 --- a/boomerang/src/main/java/boomerang/global/response/ErrorCode.java +++ b/boomerang/src/main/java/boomerang/global/response/ErrorCode.java @@ -28,7 +28,8 @@ public enum ErrorCode { // Board BOARD_NOT_FOUND_ERROR(HttpStatus.BAD_REQUEST, "EB001", "Board Not Found Error"), BOARD_DONT_HAS_OWNERSHIP_ERROR(HttpStatus.BAD_REQUEST, "EB002", "수정 또는 삭제 권한이 없는 게시글입니다"), - IMAGE_COUNT_MISMATCH_ERROR(HttpStatus.BAD_REQUEST, "EB003", "이미지 파일 수가 콘텐츠의 이미지 태그 수와 일치하지 않습니다"), + IMAGE_COUNT_MISMATCH_ERROR(HttpStatus.BAD_REQUEST, "EB003", + "이미지 파일 수가 콘텐츠의 이미지 태그 수와 일치하지 않습니다"), // Comment COMMENT_IS_NULL(HttpStatus.BAD_REQUEST, "CM001", "댓글은 빈 내용일 수 없습니다."), @@ -39,6 +40,7 @@ public enum ErrorCode { // Member MEMBER_NON_EXISTENT(HttpStatus.BAD_REQUEST, "MB001", "해당 멤버를 찾을 수 없습니다."), LOGIN_REQUIRED(HttpStatus.BAD_REQUEST, "MB002", "로그인이 필요합니다."), + IMAGE_REQUIRED_ERROR(HttpStatus.BAD_REQUEST, "MB003", "프로필 이미지 파일이 필요합니다."), // Mentor MENTOR_ALREADY_EXISTS(HttpStatus.CONFLICT, "MT_001", "이미 멘토로 등록된 사용자입니다."), @@ -50,7 +52,8 @@ public enum ErrorCode { CONSULTATION_NOT_FOUND_ERROR(HttpStatus.NOT_FOUND, "CS002", "해당 상담은 존재하지 않습니다."), CONSULTATION_ALREADY_EXISTS(HttpStatus.NOT_FOUND, "CS003", "같은날짜에 동일한 상담이 존재합니다."), CONSULTATION_ALREADY_FINISHED(HttpStatus.NOT_FOUND, "CS004", "해당 상담은 이미 완료되었습니다."), - CONSULTATION_TIME_REQUEST_ERROR(HttpStatus.BAD_REQUEST, "CS005", "등록 가능 시간은 0시에서 23시 사이여야 합니다."), + CONSULTATION_TIME_REQUEST_ERROR(HttpStatus.BAD_REQUEST, "CS005", + "등록 가능 시간은 0시에서 23시 사이여야 합니다."), CONSULTATION_NOT_A_MENTOR(HttpStatus.UNAUTHORIZED, "CS006", "로그인한 멤버가 상담의 멘토가 아닙니다."), SCHEDULE_NOT_FOUND_ERROR(HttpStatus.NOT_FOUND, "CS007", "해당 일정은 존재하지 않습니다."), // Progress @@ -68,7 +71,8 @@ public enum ErrorCode { PROGRESS_NOT_INCLUDED_MAIN(HttpStatus.NOT_FOUND, "PG010", "유저의 피해타입은 해당 메인단계를 가지고 있지 않습니다."), PROGRESS_ALREADY_COMPLETED(HttpStatus.BAD_REQUEST, "PG011", "해당 서브단계는 이미 완료 단계입니다"), PROGRESS_ALREADY_INCOMPLETE(HttpStatus.BAD_REQUEST, "PG012", "해당 서브단계는 이미 미완료 단계입니다."), - PROGRESS_REQUEST_MAIN_STEP_IS_NOT_THE_CURRENT_STEP(HttpStatus.BAD_REQUEST, "PG013", "해당 서브단계는 유저의 현재 단계가 아닙니다."), + PROGRESS_REQUEST_MAIN_STEP_IS_NOT_THE_CURRENT_STEP(HttpStatus.BAD_REQUEST, "PG013", + "해당 서브단계는 유저의 현재 단계가 아닙니다."), SUB_STEP_INFO_NOT_FOUND(HttpStatus.BAD_REQUEST, "PG014", "해당 서브단계에 대한 정보가 존재하지 않습니다."), diff --git a/boomerang/src/main/java/boomerang/global/response/ErrorResponseDto.java b/boomerang/src/main/java/boomerang/global/response/ErrorResponseDto.java index 62fde019..5a623215 100644 --- a/boomerang/src/main/java/boomerang/global/response/ErrorResponseDto.java +++ b/boomerang/src/main/java/boomerang/global/response/ErrorResponseDto.java @@ -1,6 +1,7 @@ package boomerang.global.response; public record ErrorResponseDto(String code, String message) { + public ErrorResponseDto(ErrorCode errorCode) { this(errorCode.getCode(), errorCode.getMessage()); } diff --git a/boomerang/src/main/java/boomerang/global/response/PageResponseDto.java b/boomerang/src/main/java/boomerang/global/response/PageResponseDto.java index 50178e5b..03d8e19e 100644 --- a/boomerang/src/main/java/boomerang/global/response/PageResponseDto.java +++ b/boomerang/src/main/java/boomerang/global/response/PageResponseDto.java @@ -2,14 +2,14 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; +import java.util.List; import lombok.Getter; import org.springframework.data.domain.Page; -import java.util.List; - @Getter @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class PageResponseDto { + private int totalPage; private int currentPage; private List content; diff --git a/boomerang/src/main/java/boomerang/global/utils/CookieUtil.java b/boomerang/src/main/java/boomerang/global/utils/CookieUtil.java index 817c6ede..50369f53 100644 --- a/boomerang/src/main/java/boomerang/global/utils/CookieUtil.java +++ b/boomerang/src/main/java/boomerang/global/utils/CookieUtil.java @@ -2,12 +2,10 @@ import boomerang.global.exception.BusinessException; import boomerang.global.response.ErrorCode; -import jakarta.servlet.http.Cookie; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseCookie; - import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseCookie; public class CookieUtil { @@ -18,13 +16,13 @@ public class CookieUtil { public static ResponseCookie createAuthorizationCookie(String value) { return ResponseCookie.from(Authorization, value) - .path("/") - .httpOnly(false) - .secure(true) - .sameSite("None") - .domain(serverIp) - .maxAge(60 * 60 * 60) // 쿠키 수명 설정 - .build(); + .path("/") + .httpOnly(false) + .secure(true) + .sameSite("None") + .domain(serverIp) + .maxAge(60 * 60 * 60) // 쿠키 수명 설정 + .build(); } @@ -34,13 +32,13 @@ public static ResponseCookie createNicknameCookies(String value) { String encodedValue = URLEncoder.encode(value, StandardCharsets.UTF_8); return ResponseCookie.from(Nickname, encodedValue) - .path("/") - .httpOnly(false) // HTTP 전용 아님 - .secure(true) // HTTPS 전송을 위한 설정 - .sameSite("None") // 크로스 도메인 요청에서도 쿠키 전송 가능 - .domain(serverIp) - .maxAge(60 * 60 * 60) // 쿠키 수명 설정 - .build(); + .path("/") + .httpOnly(false) // HTTP 전용 아님 + .secure(true) // HTTPS 전송을 위한 설정 + .sameSite("None") // 크로스 도메인 요청에서도 쿠키 전송 가능 + .domain(serverIp) + .maxAge(60 * 60 * 60) // 쿠키 수명 설정 + .build(); } catch (Exception e) { throw new BusinessException(ErrorCode.COOKIES_ERROR); diff --git a/boomerang/src/main/java/boomerang/global/utils/JwtFilter.java b/boomerang/src/main/java/boomerang/global/utils/JwtFilter.java index 42c9758f..0dc5e450 100644 --- a/boomerang/src/main/java/boomerang/global/utils/JwtFilter.java +++ b/boomerang/src/main/java/boomerang/global/utils/JwtFilter.java @@ -6,17 +6,15 @@ import boomerang.member.domain.MemberRole; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; -import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; import lombok.extern.slf4j.Slf4j; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.OncePerRequestFilter; -import java.io.IOException; - @Slf4j public class JwtFilter extends OncePerRequestFilter { @@ -24,14 +22,16 @@ public class JwtFilter extends OncePerRequestFilter { private final PrincipalService principalService; private final ClientServerProperties clientServerProperties; - public JwtFilter(JwtUtil jwtUtil, PrincipalService principalService, ClientServerProperties clientServerProperties) { + public JwtFilter(JwtUtil jwtUtil, PrincipalService principalService, + ClientServerProperties clientServerProperties) { this.jwtUtil = jwtUtil; this.principalService = principalService; this.clientServerProperties = clientServerProperties; } @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { String token = request.getHeader("Authorization"); if (token == null || token.isBlank()) { @@ -72,13 +72,14 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse PrincipalDetails memberDetail = (PrincipalDetails) principalService.loadUserByEmail(email); if (memberDetail.getMemberRole().equals(MemberRole.INCOMPLETE_USER) - && !("/api/v1/member/nickname".equals(path) && "PUT".equalsIgnoreCase(method))) { + && !("/api/v1/member/nickname".equals(path) && "PUT".equalsIgnoreCase(method))) { response.sendRedirect(clientServerProperties.getWelcome()); filterChain.doFilter(request, response); } //스프링 시큐리티 인증 토큰 생성 - Authentication authToken = new UsernamePasswordAuthenticationToken(memberDetail, null, memberDetail.getAuthorities()); + Authentication authToken = new UsernamePasswordAuthenticationToken(memberDetail, null, + memberDetail.getAuthorities()); //세션에 사용자 등록 SecurityContextHolder.getContext().setAuthentication(authToken); diff --git a/boomerang/src/main/java/boomerang/global/utils/JwtUtil.java b/boomerang/src/main/java/boomerang/global/utils/JwtUtil.java index 4248ab73..3f1e84c0 100644 --- a/boomerang/src/main/java/boomerang/global/utils/JwtUtil.java +++ b/boomerang/src/main/java/boomerang/global/utils/JwtUtil.java @@ -4,14 +4,14 @@ import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; import jakarta.annotation.PostConstruct; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - import java.security.Key; import java.util.Date; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; @Component public class JwtUtil { + // application.properties에서 시크릿 키와 만료시간을 가져옵니다. @Value("${jwt.secret-key}") private String secretKey; @@ -30,29 +30,29 @@ public void init() { public String generateToken(Long memberId, String email) { return Jwts.builder() - .setSubject(memberId.toString()) - .claim("email", email) - .setIssuedAt(new Date()) - .setExpiration(new Date(System.currentTimeMillis() + expirationTime)) // 설정된 만료 시간 사용 - .signWith(key) - .compact(); + .setSubject(memberId.toString()) + .claim("email", email) + .setIssuedAt(new Date()) + .setExpiration(new Date(System.currentTimeMillis() + expirationTime)) // 설정된 만료 시간 사용 + .signWith(key) + .compact(); } public Claims extractClaims(String token) { Claims claims = Jwts.parserBuilder() - .setSigningKey(key) - .build() - .parseClaimsJws(token) - .getBody(); + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody(); return claims; } public String getEmail(String token) { Claims claims = Jwts.parserBuilder() - .setSigningKey(key) - .build() - .parseClaimsJws(token) - .getBody(); + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody(); return claims.get("email", String.class); } diff --git a/boomerang/src/main/java/boomerang/global/utils/MainStepEnumConverter.java b/boomerang/src/main/java/boomerang/global/utils/MainStepEnumConverter.java index be36701f..0f1d76f8 100644 --- a/boomerang/src/main/java/boomerang/global/utils/MainStepEnumConverter.java +++ b/boomerang/src/main/java/boomerang/global/utils/MainStepEnumConverter.java @@ -6,6 +6,7 @@ @Component public class MainStepEnumConverter implements Converter { + @Override public MainStepEnum convert(String value) { return MainStepEnum.fromStepName(value); diff --git a/boomerang/src/main/java/boomerang/global/utils/MultipartJackson2HttpMessageConverter.java b/boomerang/src/main/java/boomerang/global/utils/MultipartJackson2HttpMessageConverter.java index ff65d8d6..a1b091d8 100644 --- a/boomerang/src/main/java/boomerang/global/utils/MultipartJackson2HttpMessageConverter.java +++ b/boomerang/src/main/java/boomerang/global/utils/MultipartJackson2HttpMessageConverter.java @@ -1,12 +1,11 @@ package boomerang.global.utils; import com.fasterxml.jackson.databind.ObjectMapper; +import java.lang.reflect.Type; import org.springframework.http.MediaType; import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter; import org.springframework.stereotype.Component; -import java.lang.reflect.Type; - @Component public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter { diff --git a/boomerang/src/main/java/boomerang/global/utils/ResponseHelper.java b/boomerang/src/main/java/boomerang/global/utils/ResponseHelper.java index 6f0bb1c6..db305672 100644 --- a/boomerang/src/main/java/boomerang/global/utils/ResponseHelper.java +++ b/boomerang/src/main/java/boomerang/global/utils/ResponseHelper.java @@ -15,19 +15,21 @@ private ResponseHelper() { public static ResponseEntity createErrorResponse(ErrorCode errorCode) { ErrorResponseDto errorResponseDto = new ErrorResponseDto(errorCode); return ResponseEntity.status(errorCode.getStatus()) - .body(errorResponseDto); + .body(errorResponseDto); } - public static ResponseEntity createErrorResponse(ErrorCode errorCode, String errorMessage) { + public static ResponseEntity createErrorResponse(ErrorCode errorCode, + String errorMessage) { ErrorResponseDto errorResponseDto = new ErrorResponseDto(errorCode, errorMessage); return ResponseEntity.status(errorCode.getStatus()) - .body(errorResponseDto); + .body(errorResponseDto); } - public static ResponseEntity createErrorResponse(ErrorCode errorCode,HttpStatus status, String errorMessage) { + public static ResponseEntity createErrorResponse(ErrorCode errorCode, + HttpStatus status, String errorMessage) { ErrorResponseDto errorResponseDto = new ErrorResponseDto(errorCode, errorMessage); return ResponseEntity.status(errorCode.getStatus()) - .body(errorResponseDto); + .body(errorResponseDto); } } \ No newline at end of file diff --git a/boomerang/src/main/java/boomerang/global/utils/SubStepEnumConverter.java b/boomerang/src/main/java/boomerang/global/utils/SubStepEnumConverter.java index 09723bb4..1d58407d 100644 --- a/boomerang/src/main/java/boomerang/global/utils/SubStepEnumConverter.java +++ b/boomerang/src/main/java/boomerang/global/utils/SubStepEnumConverter.java @@ -6,6 +6,7 @@ @Component public class SubStepEnumConverter implements Converter { + @Override public SubStepEnum convert(String value) { return SubStepEnum.fromStepName(value); diff --git a/boomerang/src/main/java/boomerang/kakao/controller/KakaoController.java b/boomerang/src/main/java/boomerang/kakao/controller/KakaoController.java index e4e3ed70..264a8ae8 100644 --- a/boomerang/src/main/java/boomerang/kakao/controller/KakaoController.java +++ b/boomerang/src/main/java/boomerang/kakao/controller/KakaoController.java @@ -9,24 +9,30 @@ import boomerang.kakao.domain.KakaoMember; import boomerang.kakao.dto.KakaoTokenDto; import boomerang.kakao.dto.KakaoTokenResponseDto; -import boomerang.kakao.dto.MemberStatusDto; import boomerang.kakao.service.KakaoService; import boomerang.member.domain.Member; import boomerang.member.dto.MemberLoginDto; import boomerang.member.service.MemberService; import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.io.IOException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; @Slf4j @RestController @RequestMapping("/api/v1/auth") public class KakaoController { + private final KakaoService kakaoService; private final MemberService memberService; private final JwtUtil jwtUtil; @@ -39,9 +45,9 @@ public class KakaoController { private final ClientServerProperties clientServerProperties; public KakaoController(KakaoService kakaoService, - MemberService memberService, - JwtUtil jwtUtil, - ClientServerProperties clientServerProperties) { + MemberService memberService, + JwtUtil jwtUtil, + ClientServerProperties clientServerProperties) { this.kakaoService = kakaoService; this.memberService = memberService; this.jwtUtil = jwtUtil; @@ -49,36 +55,37 @@ public KakaoController(KakaoService kakaoService, } @PostMapping("/login/kakao") - public ResponseEntity loginKakao(HttpServletResponse response,@RequestBody KakaoTokenDto kakaoTokenDto) throws IOException { + public ResponseEntity loginKakao(HttpServletResponse response, + @RequestBody KakaoTokenDto kakaoTokenDto) throws IOException { KakaoMember kakaoMember = kakaoService.getKakaoProfile(kakaoTokenDto); Member member = memberService.loginKakaoMember(kakaoMember); String token = jwtUtil.generateToken(member.getId(), member.getEmail()); - response.addHeader(Authorization,token); + response.addHeader(Authorization, token); System.out.println("member = " + member); return ResponseEntity.status(HttpStatus.OK) - .body(new MemberLoginDto(member)); + .body(new MemberLoginDto(member)); } - @GetMapping("/login") public void authorize(HttpServletResponse response) throws IOException { String redirectUri = String.format("http://%s:8080/api/v1/auth/login/callback", serverIp); String authorizationUrl = String.format( - "https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=%s&redirect_uri=%s", - clientId, redirectUri + "https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=%s&redirect_uri=%s", + clientId, redirectUri ); response.sendRedirect(authorizationUrl); } @GetMapping("/login/callback") @ResponseBody - public ResponseEntity token(@RequestParam("code") String code, HttpServletResponse response) throws IOException { + public ResponseEntity token(@RequestParam("code") String code, + HttpServletResponse response) throws IOException { KakaoTokenResponseDto kakaoTokenResponseDto = kakaoService.getAccessTokenFromKakao(code); // KakaoMember kakaoMember = kakaoService.getKakaoProfile(kakaoTokenResponseDto); // Member member = memberService.loginKakaoMember(kakaoMember); return ResponseEntity.status(HttpStatus.OK) - .body(kakaoTokenResponseDto.accessToken); + .body(kakaoTokenResponseDto.accessToken); } @@ -86,7 +93,8 @@ public ResponseEntity token(@RequestParam("code") String code, HttpServl // RequestBody에서 발생한 에러가 HttpMessageNotReadableException 로 Wrapping 이 되는 문제가 발생한다 // 때문에, 해당 에러로 Wrapping 되기 전 Controller 에서 Domain Error 를 처리해주었다 @ExceptionHandler(DomainValidationException.class) - public ResponseEntity handleOptionValidException(DomainValidationException e) { + public ResponseEntity handleOptionValidException( + DomainValidationException e) { log.error(e.toString()); return ResponseHelper.createErrorResponse(e.getErrorCode()); } @@ -95,11 +103,12 @@ private void setCookies(HttpServletResponse response, Member member) { String token = jwtUtil.generateToken(member.getId(), member.getEmail()); response.addHeader("Set-Cookie", CookieUtil.createAuthorizationCookie(token).toString()); if (member.isComplete()) { - response.addHeader("Set-Cookie", CookieUtil.createNicknameCookies(member.getNickname()).toString()); + response.addHeader("Set-Cookie", + CookieUtil.createNicknameCookies(member.getNickname()).toString()); } } - private String getRedirectUtil( Member member) { + private String getRedirectUtil(Member member) { if (member.isComplete()) { return clientServerProperties.getHome(); } diff --git a/boomerang/src/main/java/boomerang/kakao/domain/KakaoMember.java b/boomerang/src/main/java/boomerang/kakao/domain/KakaoMember.java index 34bbe725..7400fee7 100644 --- a/boomerang/src/main/java/boomerang/kakao/domain/KakaoMember.java +++ b/boomerang/src/main/java/boomerang/kakao/domain/KakaoMember.java @@ -2,6 +2,7 @@ public record KakaoMember(KakaoProfile kakaoProfile) { + public String nickname() { return kakaoProfile.nickname(); } @@ -10,6 +11,9 @@ public String email() { return kakaoProfile.email(); } + public String profileImage() { + return kakaoProfile.profileImage(); + } public Long id() { return kakaoProfile.id(); diff --git a/boomerang/src/main/java/boomerang/kakao/domain/KakaoProfile.java b/boomerang/src/main/java/boomerang/kakao/domain/KakaoProfile.java index 303e8986..1979a794 100644 --- a/boomerang/src/main/java/boomerang/kakao/domain/KakaoProfile.java +++ b/boomerang/src/main/java/boomerang/kakao/domain/KakaoProfile.java @@ -1,21 +1,57 @@ package boomerang.kakao.domain; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) -public record KakaoProfile(Long id, KakaoAccount kakaoAccount, Properties properties) { +public record KakaoProfile( + Long id, + @JsonProperty("connected_at") String connectedAt, + Properties properties, + KakaoAccount kakaoAccount +) { + public String nickname() { - return properties().nickname(); + return properties.nickname(); } public String email() { return kakaoAccount.email(); } - record Properties(String nickname) { + public String profileImage() { + return properties.profileImage(); + } + + record Properties( + String nickname, + @JsonProperty("profile_image") String profileImage, + @JsonProperty("thumbnail_image") String thumbnailImage + ) { + + } + + record KakaoAccount( + @JsonProperty("profile_nickname_needs_agreement") Boolean profileNicknameNeedsAgreement, + @JsonProperty("profile_image_needs_agreement") Boolean profileImageNeedsAgreement, + Profile profile, + @JsonProperty("has_email") Boolean hasEmail, + @JsonProperty("email_needs_agreement") Boolean emailNeedsAgreement, + @JsonProperty("is_email_valid") Boolean isEmailValid, + @JsonProperty("is_email_verified") Boolean isEmailVerified, + String email + ) { + } - record KakaoAccount(String email) { + record Profile( + String nickname, + @JsonProperty("thumbnail_image_url") String thumbnailImageUrl, + @JsonProperty("profile_image_url") String profileImageUrl, + @JsonProperty("is_default_image") Boolean isDefaultImage, + @JsonProperty("is_default_nickname") Boolean isDefaultNickname + ) { + } -} +} \ No newline at end of file diff --git a/boomerang/src/main/java/boomerang/kakao/dto/KakaoTokenDto.java b/boomerang/src/main/java/boomerang/kakao/dto/KakaoTokenDto.java index ed5106f0..a8b637fd 100644 --- a/boomerang/src/main/java/boomerang/kakao/dto/KakaoTokenDto.java +++ b/boomerang/src/main/java/boomerang/kakao/dto/KakaoTokenDto.java @@ -10,5 +10,6 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class KakaoTokenDto { + public String accessToken; } diff --git a/boomerang/src/main/java/boomerang/kakao/exception/KakaoNotFoundException.java b/boomerang/src/main/java/boomerang/kakao/exception/KakaoNotFoundException.java index 926ff1ca..f1d5e79b 100644 --- a/boomerang/src/main/java/boomerang/kakao/exception/KakaoNotFoundException.java +++ b/boomerang/src/main/java/boomerang/kakao/exception/KakaoNotFoundException.java @@ -4,6 +4,7 @@ import boomerang.global.response.ErrorCode; public class KakaoNotFoundException extends BusinessException { + public KakaoNotFoundException() { super(ErrorCode.TEMPLATE_NOT_FOUND_ERROR); } diff --git a/boomerang/src/main/java/boomerang/kakao/exception/KakaoValidException.java b/boomerang/src/main/java/boomerang/kakao/exception/KakaoValidException.java index be8d02af..2f242d5d 100644 --- a/boomerang/src/main/java/boomerang/kakao/exception/KakaoValidException.java +++ b/boomerang/src/main/java/boomerang/kakao/exception/KakaoValidException.java @@ -4,6 +4,7 @@ import boomerang.global.response.ErrorCode; public class KakaoValidException extends DomainValidationException { + public KakaoValidException(ErrorCode errorCode) { super(errorCode); } diff --git a/boomerang/src/main/java/boomerang/kakao/service/KakaoService.java b/boomerang/src/main/java/boomerang/kakao/service/KakaoService.java index 57d29812..db23d1d9 100644 --- a/boomerang/src/main/java/boomerang/kakao/service/KakaoService.java +++ b/boomerang/src/main/java/boomerang/kakao/service/KakaoService.java @@ -1,6 +1,8 @@ package boomerang.kakao.service; -import boomerang.global.exception.BusinessException; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED; + import boomerang.global.exception.KakaoException; import boomerang.kakao.domain.KakaoMember; import boomerang.kakao.domain.KakaoProfile; @@ -14,9 +16,6 @@ import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestClient; -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED; - @Service public class KakaoService { @@ -39,26 +38,17 @@ public KakaoTokenResponseDto getAccessTokenFromKakao(String code) { MultiValueMap map = new LinkedMultiValueMap<>(); map.add("grant_type", "authorization_code"); map.add("client_id", clientId); - map.add("redirect_uri", String.format("http://%s:8080/api/v1/auth/login/callback", serverIp)); + map.add("redirect_uri", + String.format("http://%s:8080/api/v1/auth/login/callback", serverIp)); map.add("code", code); return restClient.post() - .uri("https://kauth.kakao.com/oauth/token") - .contentType(CONTENT_TYPE) - .body(map) - .retrieve() - .toEntity(KakaoTokenResponseDto.class) - .getBody(); - } - - public KakaoMember getKakaoProfile(KakaoTokenResponseDto tokenResponse) { - KakaoProfile kakaoProfile = restClient.post().uri("https://kapi.kakao.com/v2/user/me") // 쿼리파라미터 없이 요청시 전체정보 받음 - .contentType(CONTENT_TYPE).header(AUTHORIZATION, BEARER + tokenResponse.accessToken) - .retrieve().toEntity(KakaoProfile.class).getBody(); - - KakaoMember kakaoMember = new KakaoMember(kakaoProfile); - return kakaoMember; - + .uri("https://kauth.kakao.com/oauth/token") + .contentType(CONTENT_TYPE) + .body(map) + .retrieve() + .toEntity(KakaoTokenResponseDto.class) + .getBody(); } public KakaoMember getKakaoProfile(KakaoTokenDto kakaoTokenDto) { @@ -66,15 +56,16 @@ public KakaoMember getKakaoProfile(KakaoTokenDto kakaoTokenDto) { try { kakaoProfile = restClient.post() - .uri("https://kapi.kakao.com/v2/user/me") // 쿼리파라미터 없이 요청시 전체정보 받음 - .contentType(CONTENT_TYPE).header(AUTHORIZATION, BEARER + kakaoTokenDto.getAccessToken()) - .retrieve(). - toEntity(KakaoProfile.class).getBody(); - }catch (HttpClientErrorException e) { + .uri("https://kapi.kakao.com/v2/user/me") // 쿼리파라미터 없이 요청시 전체정보 받음 + .contentType(CONTENT_TYPE) + .header(AUTHORIZATION, BEARER + kakaoTokenDto.getAccessToken()) + .retrieve(). + toEntity(KakaoProfile.class).getBody(); + } catch (HttpClientErrorException e) { // 카카오 API에서 반환한 상태 코드와 응답 본문을 출력 System.out.println("HTTP Status Code: " + e.getStatusCode()); System.out.println("Error Response Body: " + e.getResponseBodyAsString()); - throw new KakaoException(e.getStatusCode(),e.getResponseBodyAsString()); + throw new KakaoException(e.getStatusCode(), e.getResponseBodyAsString()); } KakaoMember kakaoMember = new KakaoMember(kakaoProfile); diff --git a/boomerang/src/main/java/boomerang/like/controller/LikeController.java b/boomerang/src/main/java/boomerang/like/controller/LikeController.java index d34d9526..823709ee 100644 --- a/boomerang/src/main/java/boomerang/like/controller/LikeController.java +++ b/boomerang/src/main/java/boomerang/like/controller/LikeController.java @@ -8,7 +8,12 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor @@ -19,8 +24,8 @@ public class LikeController { @GetMapping("/{board_id}/likes") public ResponseEntity getLikesByBoardId( - @AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable(name = "board_id") Long boardId) { + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable(name = "board_id") Long boardId) { String email = null; if (principalDetails != null) { email = principalDetails.getMemberEmail(); @@ -32,16 +37,17 @@ public ResponseEntity getLikesByBoardId( @PostMapping("/{board_id}/likes") public ResponseEntity createLike( - @AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable(name = "board_id") Long boardId) { - LikeResponseDto likeResponseDto = likeService.createLike(principalDetails.getMemberEmail(), boardId); + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable(name = "board_id") Long boardId) { + LikeResponseDto likeResponseDto = likeService.createLike(principalDetails.getMemberEmail(), + boardId); return ResponseEntity.status(HttpStatus.CREATED).body(likeResponseDto); } @DeleteMapping("/{board_id}/likes") public ResponseEntity deleteLike( - @AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable(name = "board_id") Long boardId) { + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable(name = "board_id") Long boardId) { likeService.deleteLike(principalDetails.getMemberEmail(), boardId); return ResponseEntity.noContent().build(); } diff --git a/boomerang/src/main/java/boomerang/like/domain/Like.java b/boomerang/src/main/java/boomerang/like/domain/Like.java index e3a09e95..8b49f7a7 100644 --- a/boomerang/src/main/java/boomerang/like/domain/Like.java +++ b/boomerang/src/main/java/boomerang/like/domain/Like.java @@ -2,7 +2,16 @@ import boomerang.board.domain.Board; import boomerang.member.domain.Member; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import java.time.LocalDateTime; +import java.util.Objects; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; @@ -11,15 +20,13 @@ import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; -import java.time.LocalDateTime; -import java.util.Objects; - @Getter @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor @Table(name = "likes") public class Like { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -51,9 +58,12 @@ public Like(Member member, Board board) { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) + if (this == o) { + return true; + } + if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) { return false; + } Like item = (Like) o; return Objects.equals(id, item.id); } diff --git a/boomerang/src/main/java/boomerang/like/dto/LikeResponseDto.java b/boomerang/src/main/java/boomerang/like/dto/LikeResponseDto.java index 0e619576..087341c7 100644 --- a/boomerang/src/main/java/boomerang/like/dto/LikeResponseDto.java +++ b/boomerang/src/main/java/boomerang/like/dto/LikeResponseDto.java @@ -4,18 +4,18 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; +import java.time.LocalDateTime; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; -import java.time.LocalDateTime; - @Getter @ToString @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class LikeResponseDto { + private Long id; // 좋아요 ID private String memberName; // 좋아요를 누른 사용자 이름 private Long boardId; // 게시글 ID diff --git a/boomerang/src/main/java/boomerang/like/dto/LikeSummaryResponseDto.java b/boomerang/src/main/java/boomerang/like/dto/LikeSummaryResponseDto.java index 8093d6bb..ee733984 100644 --- a/boomerang/src/main/java/boomerang/like/dto/LikeSummaryResponseDto.java +++ b/boomerang/src/main/java/boomerang/like/dto/LikeSummaryResponseDto.java @@ -12,6 +12,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class LikeSummaryResponseDto { + private int count; private boolean isLiked; diff --git a/boomerang/src/main/java/boomerang/like/exception/LikeValidException.java b/boomerang/src/main/java/boomerang/like/exception/LikeValidException.java index 259bb530..a7271c12 100644 --- a/boomerang/src/main/java/boomerang/like/exception/LikeValidException.java +++ b/boomerang/src/main/java/boomerang/like/exception/LikeValidException.java @@ -4,6 +4,7 @@ import boomerang.global.response.ErrorCode; public class LikeValidException extends DomainValidationException { + public LikeValidException(ErrorCode errorCode) { super(errorCode); } diff --git a/boomerang/src/main/java/boomerang/like/exception/UnauthorizedLikeDeleteException.java b/boomerang/src/main/java/boomerang/like/exception/UnauthorizedLikeDeleteException.java index b60b114b..f4851305 100644 --- a/boomerang/src/main/java/boomerang/like/exception/UnauthorizedLikeDeleteException.java +++ b/boomerang/src/main/java/boomerang/like/exception/UnauthorizedLikeDeleteException.java @@ -4,6 +4,7 @@ import boomerang.global.response.ErrorCode; public class UnauthorizedLikeDeleteException extends DomainValidationException { + public UnauthorizedLikeDeleteException() { super(ErrorCode.NOT_MEMBERS_LIKE_ERROR); } diff --git a/boomerang/src/main/java/boomerang/like/repository/LikeRepository.java b/boomerang/src/main/java/boomerang/like/repository/LikeRepository.java index a07d02ed..6a53cf25 100644 --- a/boomerang/src/main/java/boomerang/like/repository/LikeRepository.java +++ b/boomerang/src/main/java/boomerang/like/repository/LikeRepository.java @@ -3,9 +3,8 @@ import boomerang.board.domain.Board; import boomerang.like.domain.Like; import boomerang.member.domain.Member; -import org.springframework.data.jpa.repository.JpaRepository; - import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; public interface LikeRepository extends JpaRepository { diff --git a/boomerang/src/main/java/boomerang/like/service/LikeService.java b/boomerang/src/main/java/boomerang/like/service/LikeService.java index 989bab4e..89dbae90 100644 --- a/boomerang/src/main/java/boomerang/like/service/LikeService.java +++ b/boomerang/src/main/java/boomerang/like/service/LikeService.java @@ -59,14 +59,14 @@ public void deleteLike(String email, Long boardId) { Board board = boardService.getBoard(boardId); Like like = likeRepository.findByMemberAndBoardAndIsDeletedFalse(loginMember, board) - .orElseThrow(() -> new BusinessException(ErrorCode.LIKE_NOT_FOUND)); + .orElseThrow(() -> new BusinessException(ErrorCode.LIKE_NOT_FOUND)); like.delete(); board.decreaseLikeCount(); } private LikeResponseDto createLikeResponseDto(Like like, boolean isUserLoggedIn, - Member loginMember) { + Member loginMember) { if (!isUserLoggedIn) { return new LikeResponseDto(like, false); } diff --git a/boomerang/src/main/java/boomerang/member/controller/MemberController.java b/boomerang/src/main/java/boomerang/member/controller/MemberController.java index e1f65cb5..92256943 100644 --- a/boomerang/src/main/java/boomerang/member/controller/MemberController.java +++ b/boomerang/src/main/java/boomerang/member/controller/MemberController.java @@ -1,28 +1,39 @@ package boomerang.member.controller; -import boomerang.member.domain.Member; -import boomerang.member.dto.MemberCreateRequestDto; -import boomerang.member.service.MemberService; import boomerang.global.exception.DomainValidationException; import boomerang.global.oauth.dto.PrincipalDetails; import boomerang.global.response.ErrorResponseDto; -import boomerang.global.utils.CookieUtil; import boomerang.global.utils.ResponseHelper; import boomerang.member.domain.Member; -import boomerang.member.dto.*; +import boomerang.member.dto.MemberCreateRequestDto; +import boomerang.member.dto.MemberLoginDto; +import boomerang.member.dto.MemberResponseDto; +import boomerang.member.dto.NicknameUpdateRequestDto; +import boomerang.member.dto.RandomNicknameCreateResponseDTO; import boomerang.member.service.MemberService; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; @Slf4j @RestController @RequestMapping("/api/v1/member") public class MemberController { + private final MemberService memberService; public static String Authorization = "Authorization"; @@ -35,33 +46,36 @@ public MemberController(MemberService memberService) { public ResponseEntity getMemberById(@PathVariable(name = "id") Long id) { Member member = memberService.getMember(id); return ResponseEntity.status(HttpStatus.OK) - .body(member); + .body(member); } // 시큐리티 필터 테스트 컨트롤러 @GetMapping - public ResponseEntity getMember( - @AuthenticationPrincipal PrincipalDetails principalDetails) { + public ResponseEntity getMember( + @AuthenticationPrincipal PrincipalDetails principalDetails) { Member member = memberService.getMemberByEmail(principalDetails.getMemberEmail()); return ResponseEntity.status(HttpStatus.OK) - .body(member); + .body(new MemberResponseDto(member)); } @PostMapping - public ResponseEntity createMember(@RequestBody MemberCreateRequestDto memberCreateRequestDTO, HttpServletResponse response) { - String token = memberService.createMember(memberCreateRequestDTO.toMemberCreateServiceDto()); + public ResponseEntity createMember( + @RequestBody MemberCreateRequestDto memberCreateRequestDTO, HttpServletResponse response) { + String token = memberService.createMember( + memberCreateRequestDTO.toMemberCreateServiceDto()); response.addHeader("Authorization", "Bearer " + token); return ResponseEntity.status(HttpStatus.CREATED) - .build(); + .build(); } @GetMapping("/login") - public ResponseEntity loginMember(@RequestBody MemberCreateRequestDto memberCreateRequestDTO, HttpServletResponse response) { + public ResponseEntity loginMember( + @RequestBody MemberCreateRequestDto memberCreateRequestDTO, HttpServletResponse response) { String token = memberService.loginMember(memberCreateRequestDTO.toMemberCreateServiceDto()); response.addHeader("Authorization", "Bearer " + token); return ResponseEntity.status(HttpStatus.OK) - .build(); + .build(); } // 안쓰는 로직 : 팀원들과 상의 후 삭제 예정 @@ -85,22 +99,36 @@ public ResponseEntity loginMember(@RequestBody MemberCreateRequestDto memb public ResponseEntity generateRandomNickname() { String nickname = memberService.generateUniqueNickname(); return ResponseEntity.status(HttpStatus.CREATED) - .body(new RandomNicknameCreateResponseDTO(nickname)); + .body(new RandomNicknameCreateResponseDTO(nickname)); } @PutMapping("/nickname") - public ResponseEntity updateRandomNickname(@AuthenticationPrincipal PrincipalDetails principalDetails, - HttpServletResponse response, - @RequestBody NicknameUpdateRequestDto requestDto) { - Member member = memberService.updateNickname(principalDetails.getMemberEmail(), requestDto.getNewNickname()); + public ResponseEntity updateNickname( + @AuthenticationPrincipal PrincipalDetails principalDetails, + HttpServletResponse response, + @RequestBody NicknameUpdateRequestDto requestDto) { + Member member = memberService.updateNickname(principalDetails.getMemberEmail(), + requestDto.getNewNickname()); return ResponseEntity.status(HttpStatus.CREATED).body(new MemberLoginDto(member)); } + @PutMapping(value = "/image", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public ResponseEntity updateProfileImage( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @RequestParam(value = "image", required = true) MultipartFile image) { + + Member updatedMember = memberService.updateProfileImage(principalDetails.getMemberEmail(), + image); + + return ResponseEntity.ok(new MemberResponseDto(updatedMember)); + } + // GlobalException Handler 에서 처리할 경우, // RequestBody에서 발생한 에러가 HttpMessageNotReadableException 로 Wrapping 이 되는 문제가 발생한다 // 때문에, 해당 에러로 Wrapping 되기 전 Controller 에서 Domain Error 를 처리해주었다 @ExceptionHandler(DomainValidationException.class) - public ResponseEntity handleOptionValidException(DomainValidationException e) { + public ResponseEntity handleOptionValidException( + DomainValidationException e) { log.error(e.toString()); return ResponseHelper.createErrorResponse(e.getErrorCode()); } diff --git a/boomerang/src/main/java/boomerang/member/domain/Member.java b/boomerang/src/main/java/boomerang/member/domain/Member.java index cb99f4e0..4c6cf2dc 100644 --- a/boomerang/src/main/java/boomerang/member/domain/Member.java +++ b/boomerang/src/main/java/boomerang/member/domain/Member.java @@ -91,6 +91,7 @@ public Member(MemberServiceDto memberServiceDto) { public Member(KakaoMember kakaoMember) { this.email = kakaoMember.email(); this.memberRole = MemberRole.INCOMPLETE_USER; + this.profileImage = kakaoMember.profileImage(); } public ProgressType getProgressType() { @@ -137,4 +138,8 @@ public void updateNickname(String nickname) { public void verifyEmail() { this.emailVerified = true; } + + public void updateProfileImage(String profileImage) { + this.profileImage = profileImage; + } } diff --git a/boomerang/src/main/java/boomerang/member/domain/MemberType.java b/boomerang/src/main/java/boomerang/member/domain/MemberType.java index dfb3e4a9..d0debfb5 100644 --- a/boomerang/src/main/java/boomerang/member/domain/MemberType.java +++ b/boomerang/src/main/java/boomerang/member/domain/MemberType.java @@ -5,11 +5,11 @@ import com.fasterxml.jackson.annotation.JsonValue; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; - import java.util.Objects; @Embeddable public class MemberType { + @Column(name = "member_type") private String value; @@ -37,8 +37,12 @@ public String toString() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } MemberType that = (MemberType) o; return Objects.equals(value, that.value); } diff --git a/boomerang/src/main/java/boomerang/member/domain/ProgressStep.java b/boomerang/src/main/java/boomerang/member/domain/ProgressStep.java index 8868d0a9..fec2fcba 100644 --- a/boomerang/src/main/java/boomerang/member/domain/ProgressStep.java +++ b/boomerang/src/main/java/boomerang/member/domain/ProgressStep.java @@ -5,11 +5,11 @@ import com.fasterxml.jackson.annotation.JsonValue; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; - import java.util.Objects; @Embeddable public class ProgressStep { + @Column(name = "progress_step") private String value; @@ -37,8 +37,12 @@ public String toString() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } ProgressStep that = (ProgressStep) o; return Objects.equals(value, that.value); } diff --git a/boomerang/src/main/java/boomerang/member/domain/RandomNickname.java b/boomerang/src/main/java/boomerang/member/domain/RandomNickname.java index 5c909dd1..9adedb64 100644 --- a/boomerang/src/main/java/boomerang/member/domain/RandomNickname.java +++ b/boomerang/src/main/java/boomerang/member/domain/RandomNickname.java @@ -1,24 +1,23 @@ package boomerang.member.domain; -import org.springframework.stereotype.Component; - import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Random; +import org.springframework.stereotype.Component; @Component public class RandomNickname { private static final String[] ADJECTIVES = { - "행복한", "똑똑한", "즐거운", "강한", "빠른", "재치있는", "멋진", "훌륭한", "즐거운", - "아름다운", "기쁜", "사랑스러운", "행복한", "환상적인", "놀라운", "훌륭한", "매력적인", "긍정적인", "빛나는", - "희망찬", "용감한", "따뜻한", "신나는", "친절한", "든든한", "뛰어난", "성실한", "창의적인", - "자랑스러운", "유쾌한","귀여운" + "행복한", "똑똑한", "즐거운", "강한", "빠른", "재치있는", "멋진", "훌륭한", "즐거운", + "아름다운", "기쁜", "사랑스러운", "행복한", "환상적인", "놀라운", "훌륭한", "매력적인", "긍정적인", "빛나는", + "희망찬", "용감한", "따뜻한", "신나는", "친절한", "든든한", "뛰어난", "성실한", "창의적인", + "자랑스러운", "유쾌한", "귀여운" }; private static final String[] NOUNS = { - "크롱이","라이언", "어피치", "프로토", "네오", "무지", "콘", "튜브", "제이지", "춘식이", "죠르디", - "스카피", "앙몬드", "팬다주니어", "케로", "베로니", "콥", "빠냐","코찔이","로아" + "크롱이", "라이언", "어피치", "프로토", "네오", "무지", "콘", "튜브", "제이지", "춘식이", "죠르디", + "스카피", "앙몬드", "팬다주니어", "케로", "베로니", "콥", "빠냐", "코찔이", "로아" }; private static final Random RANDOM = new Random(); @@ -29,7 +28,6 @@ public String generateRandomNickname() { // 랜덤 명사 String noun = NOUNS[RANDOM.nextInt(NOUNS.length)]; - // 현재 시간의 밀리초 가져오기 String millisString = LocalDateTime.now().format(DateTimeFormatter.ofPattern("SSS")); int millis = Integer.parseInt(millisString) % 100; // 두 자리만 사용 diff --git a/boomerang/src/main/java/boomerang/member/domain/ReturnDeposit.java b/boomerang/src/main/java/boomerang/member/domain/ReturnDeposit.java index f1eb8611..db086eb1 100644 --- a/boomerang/src/main/java/boomerang/member/domain/ReturnDeposit.java +++ b/boomerang/src/main/java/boomerang/member/domain/ReturnDeposit.java @@ -5,11 +5,11 @@ import com.fasterxml.jackson.annotation.JsonValue; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; - import java.util.Objects; @Embeddable public class ReturnDeposit { + @Column(name = "return_deposit") private int value; @@ -37,8 +37,12 @@ public int getValue() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } ReturnDeposit that = (ReturnDeposit) o; return Objects.equals(value, that.value); } diff --git a/boomerang/src/main/java/boomerang/member/domain/SafetyScore.java b/boomerang/src/main/java/boomerang/member/domain/SafetyScore.java index f2bedc7f..529d4ae1 100644 --- a/boomerang/src/main/java/boomerang/member/domain/SafetyScore.java +++ b/boomerang/src/main/java/boomerang/member/domain/SafetyScore.java @@ -5,11 +5,11 @@ import com.fasterxml.jackson.annotation.JsonValue; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; - import java.util.Objects; @Embeddable public class SafetyScore { + @Column(name = "safety_score") private int value; @@ -37,8 +37,12 @@ public int getValue() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } SafetyScore that = (SafetyScore) o; return Objects.equals(value, that.value); } diff --git a/boomerang/src/main/java/boomerang/member/domain/UpdatedAt.java b/boomerang/src/main/java/boomerang/member/domain/UpdatedAt.java index a0bf0843..062c97ce 100644 --- a/boomerang/src/main/java/boomerang/member/domain/UpdatedAt.java +++ b/boomerang/src/main/java/boomerang/member/domain/UpdatedAt.java @@ -5,11 +5,11 @@ import com.fasterxml.jackson.annotation.JsonValue; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; - import java.util.Objects; @Embeddable public class UpdatedAt { + @Column(name = "updated_at") private String value; @@ -37,8 +37,12 @@ public String toString() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } UpdatedAt that = (UpdatedAt) o; return Objects.equals(value, that.value); } diff --git a/boomerang/src/main/java/boomerang/member/dto/MemberCreateRequestDto.java b/boomerang/src/main/java/boomerang/member/dto/MemberCreateRequestDto.java index 4f275ced..e92733e6 100644 --- a/boomerang/src/main/java/boomerang/member/dto/MemberCreateRequestDto.java +++ b/boomerang/src/main/java/boomerang/member/dto/MemberCreateRequestDto.java @@ -6,6 +6,7 @@ @Getter @ToString public class MemberCreateRequestDto { + private String email; private String nickname; diff --git a/boomerang/src/main/java/boomerang/member/dto/MemberCreateResponseDto.java b/boomerang/src/main/java/boomerang/member/dto/MemberCreateResponseDto.java index cffbe67f..316d07b4 100644 --- a/boomerang/src/main/java/boomerang/member/dto/MemberCreateResponseDto.java +++ b/boomerang/src/main/java/boomerang/member/dto/MemberCreateResponseDto.java @@ -4,6 +4,7 @@ @Getter public class MemberCreateResponseDto { + private String email; private String nickname; diff --git a/boomerang/src/main/java/boomerang/member/dto/MemberLoginDto.java b/boomerang/src/main/java/boomerang/member/dto/MemberLoginDto.java index cb169110..7f7ebea3 100644 --- a/boomerang/src/main/java/boomerang/member/dto/MemberLoginDto.java +++ b/boomerang/src/main/java/boomerang/member/dto/MemberLoginDto.java @@ -9,6 +9,7 @@ @Getter @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class MemberLoginDto { + private MemberRole memberRole; private String nickname; diff --git a/boomerang/src/main/java/boomerang/member/dto/MemberResponseDto.java b/boomerang/src/main/java/boomerang/member/dto/MemberResponseDto.java new file mode 100644 index 00000000..3fffc39c --- /dev/null +++ b/boomerang/src/main/java/boomerang/member/dto/MemberResponseDto.java @@ -0,0 +1,35 @@ +package boomerang.member.dto; + +import boomerang.member.domain.Member; +import boomerang.member.domain.MemberRole; +import boomerang.progress.domain.ProgressType; +import lombok.Getter; + +@Getter +public class MemberResponseDto { + + private final Long memberId; + private final String email; + private final String nickname; + private final String profileImage; + private final MemberRole memberRole; + private final boolean emailVerified; + private final boolean insuranceStatus; + private final Long returnDeposit; + private final Integer safetyScore; + private final ProgressType progressType; + + public MemberResponseDto(Member member) { + this.memberId = member.getId(); + this.email = member.getEmail(); + this.nickname = member.getNickname(); + this.profileImage = member.getProfileImage(); + this.memberRole = member.getMemberRole(); + this.emailVerified = member.isEmailVerified(); + this.insuranceStatus = member.isInsuranceStatus(); + this.returnDeposit = + member.getReturnDeposit() != null ? member.getReturnDeposit().getValue() : 0L; + this.safetyScore = member.getSafetyScore() != null ? member.getSafetyScore().getValue() : 0; + this.progressType = member.getProgressType(); + } +} \ No newline at end of file diff --git a/boomerang/src/main/java/boomerang/member/dto/MemberServiceDto.java b/boomerang/src/main/java/boomerang/member/dto/MemberServiceDto.java index 1e547ad5..97573e5d 100644 --- a/boomerang/src/main/java/boomerang/member/dto/MemberServiceDto.java +++ b/boomerang/src/main/java/boomerang/member/dto/MemberServiceDto.java @@ -1,10 +1,14 @@ package boomerang.member.dto; -import boomerang.member.domain.*; +import boomerang.member.domain.MemberType; +import boomerang.member.domain.ProgressStep; +import boomerang.member.domain.ReturnDeposit; +import boomerang.member.domain.SafetyScore; import lombok.Getter; @Getter public class MemberServiceDto { + private Long id; private String email; private String nickname; diff --git a/boomerang/src/main/java/boomerang/member/dto/NicknameUpdateRequestDto.java b/boomerang/src/main/java/boomerang/member/dto/NicknameUpdateRequestDto.java index d854e039..3e9eae7e 100644 --- a/boomerang/src/main/java/boomerang/member/dto/NicknameUpdateRequestDto.java +++ b/boomerang/src/main/java/boomerang/member/dto/NicknameUpdateRequestDto.java @@ -7,6 +7,7 @@ @Getter @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class NicknameUpdateRequestDto { + private String newNickname; public String getNewNickname() { diff --git a/boomerang/src/main/java/boomerang/member/dto/RandomNicknameCreateResponseDTO.java b/boomerang/src/main/java/boomerang/member/dto/RandomNicknameCreateResponseDTO.java index 342d0d80..2f728356 100644 --- a/boomerang/src/main/java/boomerang/member/dto/RandomNicknameCreateResponseDTO.java +++ b/boomerang/src/main/java/boomerang/member/dto/RandomNicknameCreateResponseDTO.java @@ -4,9 +4,11 @@ @Getter public class RandomNicknameCreateResponseDTO { + private String nickname; - public RandomNicknameCreateResponseDTO() {} + public RandomNicknameCreateResponseDTO() { + } public RandomNicknameCreateResponseDTO(String nickname) { this.nickname = nickname; diff --git a/boomerang/src/main/java/boomerang/member/exception/MemberNotFoundException.java b/boomerang/src/main/java/boomerang/member/exception/MemberNotFoundException.java index 8052d2a5..bff35ae5 100644 --- a/boomerang/src/main/java/boomerang/member/exception/MemberNotFoundException.java +++ b/boomerang/src/main/java/boomerang/member/exception/MemberNotFoundException.java @@ -4,6 +4,7 @@ import boomerang.global.response.ErrorCode; public class MemberNotFoundException extends BusinessException { + public MemberNotFoundException() { super(ErrorCode.TEMPLATE_NOT_FOUND_ERROR); } diff --git a/boomerang/src/main/java/boomerang/member/exception/MemberValidException.java b/boomerang/src/main/java/boomerang/member/exception/MemberValidException.java index 2fbb8948..ae873913 100644 --- a/boomerang/src/main/java/boomerang/member/exception/MemberValidException.java +++ b/boomerang/src/main/java/boomerang/member/exception/MemberValidException.java @@ -4,6 +4,7 @@ import boomerang.global.response.ErrorCode; public class MemberValidException extends DomainValidationException { + public MemberValidException(ErrorCode errorCode) { super(errorCode); } diff --git a/boomerang/src/main/java/boomerang/member/repository/MemberRepository.java b/boomerang/src/main/java/boomerang/member/repository/MemberRepository.java index 57c37e31..86384e21 100644 --- a/boomerang/src/main/java/boomerang/member/repository/MemberRepository.java +++ b/boomerang/src/main/java/boomerang/member/repository/MemberRepository.java @@ -1,11 +1,11 @@ package boomerang.member.repository; import boomerang.member.domain.Member; -import org.springframework.data.jpa.repository.JpaRepository; - import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; public interface MemberRepository extends JpaRepository { + boolean existsById(Long id); boolean existsByEmail(String email); diff --git a/boomerang/src/main/java/boomerang/member/service/MemberService.java b/boomerang/src/main/java/boomerang/member/service/MemberService.java index 3db9a9b2..cb4dc0e4 100644 --- a/boomerang/src/main/java/boomerang/member/service/MemberService.java +++ b/boomerang/src/main/java/boomerang/member/service/MemberService.java @@ -1,5 +1,6 @@ package boomerang.member.service; +import boomerang.file.service.FileService; import boomerang.global.exception.BusinessException; import boomerang.global.response.ErrorCode; import boomerang.global.utils.JwtUtil; @@ -9,20 +10,28 @@ import boomerang.member.dto.MemberServiceDto; import boomerang.member.exception.MemberNotFoundException; import boomerang.member.repository.MemberRepository; -import org.springframework.stereotype.Service; - +import java.net.URL; import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +@Slf4j @Service public class MemberService { + private final MemberRepository memberRepository; private final JwtUtil jwtUtil; private final RandomNickname randomNicknameGenerator; + private final FileService fileService; - public MemberService(MemberRepository memberRepository, JwtUtil jwtUtil, RandomNickname randomNicknameGenerator) { + public MemberService(MemberRepository memberRepository, JwtUtil jwtUtil, + RandomNickname randomNicknameGenerator, FileService fileService) { this.memberRepository = memberRepository; this.jwtUtil = jwtUtil; this.randomNicknameGenerator = randomNicknameGenerator; + this.fileService = fileService; } public List getAllMembers() { @@ -31,13 +40,13 @@ public List getAllMembers() { public Member getMember(Long id) { return memberRepository.findById(id) - .orElseThrow(() -> new BusinessException(ErrorCode.MEMBER_NON_EXISTENT)); + .orElseThrow(() -> new BusinessException(ErrorCode.MEMBER_NON_EXISTENT)); } public Member getMemberByEmail(String email) { return memberRepository.findByEmail(email) - .orElseThrow(() -> new BusinessException(ErrorCode.MEMBER_NON_EXISTENT)); + .orElseThrow(() -> new BusinessException(ErrorCode.MEMBER_NON_EXISTENT)); } public String createMember(MemberServiceDto memberCreateServiceDto) { @@ -48,14 +57,14 @@ public String createMember(MemberServiceDto memberCreateServiceDto) { public Member loginKakaoMember(KakaoMember kakaoMember) { String email = kakaoMember.email(); //카카오에서 받은 이메일을 emailString으로 저장 return memberRepository.findByEmail(email) - .orElseGet(() -> memberRepository.save(new Member(kakaoMember))); + .orElseGet(() -> memberRepository.save(new Member(kakaoMember))); } public String loginMember(MemberServiceDto memberCreateServiceDto) { String email = memberCreateServiceDto.getEmail(); String nickName = memberCreateServiceDto.getNickname(); Member member = memberRepository.findByEmailAndNickname(email, nickName) - .orElseThrow(() -> new BusinessException(ErrorCode.MEMBER_NON_EXISTENT)); + .orElseThrow(() -> new BusinessException(ErrorCode.MEMBER_NON_EXISTENT)); return jwtUtil.generateToken(member.getId(), member.getEmail()); } @@ -95,4 +104,27 @@ public Member updateNickname(String email, String newNickname) { return member; } + @Transactional + public Member updateProfileImage(String email, MultipartFile image) { + log.info("Starting profile image update for email: {}", email); + + Member member = memberRepository.findByEmail(email) + .orElseThrow(() -> new BusinessException(ErrorCode.MEMBER_NON_EXISTENT)); + + try { + log.info("Attempting to upload image. Original filename: {}", + image.getOriginalFilename()); + + // S3에 이미지 업로드 + URL imageUrl = fileService.upload(email, image); + log.info("Successfully uploaded image to S3. URL: {}", imageUrl); + + member.updateProfileImage(imageUrl.toString()); + + return member; + } catch (Exception e) { + log.error("Error during image upload/update process", e); + throw new BusinessException(ErrorCode.S3_UPLOAD_ERROR); + } + } } diff --git a/boomerang/src/main/java/boomerang/mentor/controller/MentorController.java b/boomerang/src/main/java/boomerang/mentor/controller/MentorController.java index c4bcbc81..bdb871fe 100644 --- a/boomerang/src/main/java/boomerang/mentor/controller/MentorController.java +++ b/boomerang/src/main/java/boomerang/mentor/controller/MentorController.java @@ -15,7 +15,14 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor @@ -27,7 +34,7 @@ public class MentorController { // 멘토 조회 @GetMapping public ResponseEntity> getAllMentors( - @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) { + @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) { Page mentors = mentorService.getAllMentors(pageable); return ResponseEntity.ok(new PageResponseDto(mentors)); } @@ -42,24 +49,27 @@ public ResponseEntity getMentorById(@PathVariable Long id) { // 멘토 등록 @PostMapping public ResponseEntity createMentor( - @AuthenticationPrincipal PrincipalDetails principalDetails, - @Valid @RequestBody MentorCreateRequestDto mentorCreateRequestDto) { - MentorResponseDto mentorResponseDto = mentorService.createMentor(principalDetails.getMemberEmail(), mentorCreateRequestDto); + @AuthenticationPrincipal PrincipalDetails principalDetails, + @Valid @RequestBody MentorCreateRequestDto mentorCreateRequestDto) { + MentorResponseDto mentorResponseDto = mentorService.createMentor( + principalDetails.getMemberEmail(), mentorCreateRequestDto); return ResponseEntity.status(HttpStatus.CREATED).body(mentorResponseDto); } // 멘토 정보 수정 @PutMapping public ResponseEntity updateMentor( - @AuthenticationPrincipal PrincipalDetails principalDetails, - @Valid @RequestBody MentorUpdateRequestDto updateRequestDto) { - MentorResponseDto updatedMentor = mentorService.updateMentor(principalDetails.getMemberEmail(), updateRequestDto); + @AuthenticationPrincipal PrincipalDetails principalDetails, + @Valid @RequestBody MentorUpdateRequestDto updateRequestDto) { + MentorResponseDto updatedMentor = mentorService.updateMentor( + principalDetails.getMemberEmail(), updateRequestDto); return ResponseEntity.ok(updatedMentor); } // 멘토 삭제 @DeleteMapping - public ResponseEntity deleteMentor(@AuthenticationPrincipal PrincipalDetails principalDetails) { + public ResponseEntity deleteMentor( + @AuthenticationPrincipal PrincipalDetails principalDetails) { mentorService.deleteMentor(principalDetails.getMemberEmail()); return ResponseEntity.noContent().build(); } diff --git a/boomerang/src/main/java/boomerang/mentor/domain/Mentor.java b/boomerang/src/main/java/boomerang/mentor/domain/Mentor.java index e7c748cf..db55d3c0 100644 --- a/boomerang/src/main/java/boomerang/mentor/domain/Mentor.java +++ b/boomerang/src/main/java/boomerang/mentor/domain/Mentor.java @@ -4,21 +4,33 @@ import boomerang.member.domain.Member; import boomerang.mentor.dto.MentorCreateRequestDto; import boomerang.mentor.dto.MentorUpdateRequestDto; -import jakarta.persistence.*; -import lombok.Getter; -import org.hibernate.Hibernate; -import org.hibernate.annotations.CreationTimestamp; -import org.hibernate.annotations.UpdateTimestamp; - +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import lombok.Getter; +import org.hibernate.Hibernate; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; @Getter @Entity @Table(name = "mentor") public class Mentor { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -54,7 +66,8 @@ public class Mentor { protected Mentor() { } - public Mentor(MentorType mentorType, String career, String introduce, Boolean advertisementStatus, Member member, String contact) { + public Mentor(MentorType mentorType, String career, String introduce, + Boolean advertisementStatus, Member member, String contact) { this.mentorType = mentorType; this.career = career; this.introduce = introduce; @@ -66,9 +79,12 @@ public Mentor(MentorType mentorType, String career, String introduce, Boolean ad @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) + if (this == o) { + return true; + } + if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) { return false; + } Mentor mentor = (Mentor) o; return Objects.equals(id, mentor.id); } diff --git a/boomerang/src/main/java/boomerang/mentor/domain/MentorType.java b/boomerang/src/main/java/boomerang/mentor/domain/MentorType.java index 9433af40..5bb68dc3 100644 --- a/boomerang/src/main/java/boomerang/mentor/domain/MentorType.java +++ b/boomerang/src/main/java/boomerang/mentor/domain/MentorType.java @@ -4,7 +4,8 @@ @Getter public enum MentorType { - LAWYER("lawyer"), REAL_ESTATE_AGENT("realEstateAgent"), PREVIOUS_DAMAGE_RESOLVER("previousDamageResolver"); + LAWYER("lawyer"), REAL_ESTATE_AGENT("realEstateAgent"), PREVIOUS_DAMAGE_RESOLVER( + "previousDamageResolver"); private final String name; diff --git a/boomerang/src/main/java/boomerang/mentor/dto/MentorCreateRequestDto.java b/boomerang/src/main/java/boomerang/mentor/dto/MentorCreateRequestDto.java index dbc7948b..35346c68 100644 --- a/boomerang/src/main/java/boomerang/mentor/dto/MentorCreateRequestDto.java +++ b/boomerang/src/main/java/boomerang/mentor/dto/MentorCreateRequestDto.java @@ -29,7 +29,8 @@ public class MentorCreateRequestDto { @Size(min = 10, max = 20, message = "연락처는 10자 이상 20자 이하여야 합니다.") private final String contact; - public MentorCreateRequestDto(MentorType mentorType, String career, String introduce, Boolean advertisementStatus, String contact) { + public MentorCreateRequestDto(MentorType mentorType, String career, String introduce, + Boolean advertisementStatus, String contact) { this.mentorType = mentorType; this.career = career; this.introduce = introduce; diff --git a/boomerang/src/main/java/boomerang/mentor/dto/MentorUpdateRequestDto.java b/boomerang/src/main/java/boomerang/mentor/dto/MentorUpdateRequestDto.java index f1549793..91c8c19e 100644 --- a/boomerang/src/main/java/boomerang/mentor/dto/MentorUpdateRequestDto.java +++ b/boomerang/src/main/java/boomerang/mentor/dto/MentorUpdateRequestDto.java @@ -11,6 +11,7 @@ @Getter @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class MentorUpdateRequestDto { + @NotNull(message = "멘토 유형은 필수입니다.") private final MentorType mentorType; @@ -28,7 +29,8 @@ public class MentorUpdateRequestDto { @Size(min = 10, max = 20, message = "연락처는 10자 이상 20자 이하여야 합니다.") private final String contact; - public MentorUpdateRequestDto(MentorType mentorType, String career, String introduce, Boolean advertisementStatus, String contact) { + public MentorUpdateRequestDto(MentorType mentorType, String career, String introduce, + Boolean advertisementStatus, String contact) { this.mentorType = mentorType; this.career = career; this.introduce = introduce; diff --git a/boomerang/src/main/java/boomerang/mentor/repository/MentorRepository.java b/boomerang/src/main/java/boomerang/mentor/repository/MentorRepository.java index bc1c945a..0384fb49 100644 --- a/boomerang/src/main/java/boomerang/mentor/repository/MentorRepository.java +++ b/boomerang/src/main/java/boomerang/mentor/repository/MentorRepository.java @@ -2,12 +2,11 @@ import boomerang.member.domain.Member; import boomerang.mentor.domain.Mentor; +import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import java.util.Optional; - public interface MentorRepository extends JpaRepository { Page findAllByIsDeletedFalse(Pageable pageable); diff --git a/boomerang/src/main/java/boomerang/mentor/service/MentorService.java b/boomerang/src/main/java/boomerang/mentor/service/MentorService.java index 8981dd68..951ec665 100644 --- a/boomerang/src/main/java/boomerang/mentor/service/MentorService.java +++ b/boomerang/src/main/java/boomerang/mentor/service/MentorService.java @@ -100,6 +100,6 @@ public void deleteMentor(String email) { public Mentor getMentor(Long id) { return mentorRepository.findByIdAndIsDeletedFalse(id) - .orElseThrow(() -> new BusinessException(ErrorCode.MENTOR_NOT_FOUND)); + .orElseThrow(() -> new BusinessException(ErrorCode.MENTOR_NOT_FOUND)); } } diff --git a/boomerang/src/main/java/boomerang/progress/controller/ProgressController.java b/boomerang/src/main/java/boomerang/progress/controller/ProgressController.java index 5bb57c1f..5658c487 100644 --- a/boomerang/src/main/java/boomerang/progress/controller/ProgressController.java +++ b/boomerang/src/main/java/boomerang/progress/controller/ProgressController.java @@ -15,7 +15,13 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/v1") @@ -25,62 +31,79 @@ public class ProgressController { private final ProgressService progressService; @PostMapping("/progress/type")//타입 검사 - public ResponseEntity checkUserType(@AuthenticationPrincipal PrincipalDetails principalDetails, - @RequestBody ProgressTypeRequestDto progressTypeRequestDto) { - ProgressType progressTypeOfMember = progressService.checkUserType(principalDetails.getMemberEmail(), progressTypeRequestDto); - return ResponseEntity.status(HttpStatus.OK).body(new ProgressTypeResponseDto(progressTypeOfMember)); + public ResponseEntity checkUserType( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @RequestBody ProgressTypeRequestDto progressTypeRequestDto) { + ProgressType progressTypeOfMember = progressService.checkUserType( + principalDetails.getMemberEmail(), progressTypeRequestDto); + return ResponseEntity.status(HttpStatus.OK) + .body(new ProgressTypeResponseDto(progressTypeOfMember)); } @GetMapping("/progress/type")//유저의 타입 정보 - public ResponseEntity getUserType(@AuthenticationPrincipal PrincipalDetails principalDetails) { - ProgressType progressTypeOfMember = progressService.getUserType(principalDetails.getMemberEmail()); - return ResponseEntity.status(HttpStatus.OK).body(new ProgressTypeResponseDto(progressTypeOfMember)); + public ResponseEntity getUserType( + @AuthenticationPrincipal PrincipalDetails principalDetails) { + ProgressType progressTypeOfMember = progressService.getUserType( + principalDetails.getMemberEmail()); + return ResponseEntity.status(HttpStatus.OK) + .body(new ProgressTypeResponseDto(progressTypeOfMember)); } //유저의 메인 단계 목록 조회 @GetMapping("/progress") - public ResponseEntity getProgressDetails(@AuthenticationPrincipal PrincipalDetails principalDetails) { - ProgressByMainResponseDto progressByMainResponseDto = progressService.getProgressDetails(principalDetails.getMemberEmail()); + public ResponseEntity getProgressDetails( + @AuthenticationPrincipal PrincipalDetails principalDetails) { + ProgressByMainResponseDto progressByMainResponseDto = progressService.getProgressDetails( + principalDetails.getMemberEmail()); return ResponseEntity.status(HttpStatus.OK).body(progressByMainResponseDto); } //유저의 특정 메인 단계의 서브 단계 목록 조회 @GetMapping("/progress/{main}") - public ResponseEntity getSubStepsByMainStep(@AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable("main") MainStepEnum mainStepEnum) { - ProgressByMainResponseDto progressByMainResponseDto = progressService.getSubStepsByMainStep(principalDetails.getMemberEmail(), mainStepEnum); + public ResponseEntity getSubStepsByMainStep( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable("main") MainStepEnum mainStepEnum) { + ProgressByMainResponseDto progressByMainResponseDto = progressService.getSubStepsByMainStep( + principalDetails.getMemberEmail(), mainStepEnum); return ResponseEntity.status(HttpStatus.OK).body(progressByMainResponseDto); } //유저의 메인 단계의 서브 단계 목록 조회 @GetMapping("/progress/{main}/{sub}") - public ResponseEntity getSubStepStatus(@AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable("main") MainStepEnum mainStepEnum, - @PathVariable("sub") SubStepEnum subStepEnum) { + public ResponseEntity getSubStepStatus( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable("main") MainStepEnum mainStepEnum, + @PathVariable("sub") SubStepEnum subStepEnum) { validMatchingOfMainStepAndSubStep(mainStepEnum, subStepEnum); - SubStepResponseDto subStepResponseDto = progressService.getSubStepStatus(principalDetails.getMemberEmail(), mainStepEnum, subStepEnum); + SubStepResponseDto subStepResponseDto = progressService.getSubStepStatus( + principalDetails.getMemberEmail(), mainStepEnum, subStepEnum); return ResponseEntity.status(HttpStatus.OK).body(subStepResponseDto); } @PostMapping("/progress/{main}/{sub}")//특정 서브단계 완료로 변경 - public ResponseEntity completeProgress(@AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable("main") MainStepEnum mainStepEnum, - @PathVariable("sub") SubStepEnum subStepEnum) { + public ResponseEntity completeProgress( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable("main") MainStepEnum mainStepEnum, + @PathVariable("sub") SubStepEnum subStepEnum) { validMatchingOfMainStepAndSubStep(mainStepEnum, subStepEnum); - SubStepResponseDto subStepResponseDto = progressService.completeProgress(principalDetails.getMemberEmail(), mainStepEnum, subStepEnum); + SubStepResponseDto subStepResponseDto = progressService.completeProgress( + principalDetails.getMemberEmail(), mainStepEnum, subStepEnum); return ResponseEntity.status(HttpStatus.OK).body(subStepResponseDto); } @DeleteMapping("/progress/{main}/{sub}")//특정 서브단계 미완료로 변경 - public ResponseEntity revertProgressToIncomplete(@AuthenticationPrincipal PrincipalDetails principalDetails, - @PathVariable("main") MainStepEnum mainStepEnum, - @PathVariable("sub") SubStepEnum subStepEnum) { + public ResponseEntity revertProgressToIncomplete( + @AuthenticationPrincipal PrincipalDetails principalDetails, + @PathVariable("main") MainStepEnum mainStepEnum, + @PathVariable("sub") SubStepEnum subStepEnum) { validMatchingOfMainStepAndSubStep(mainStepEnum, subStepEnum); - SubStepResponseDto subStepResponseDto = progressService.revertProgressToIncomplete(principalDetails.getMemberEmail(), mainStepEnum, subStepEnum); + SubStepResponseDto subStepResponseDto = progressService.revertProgressToIncomplete( + principalDetails.getMemberEmail(), mainStepEnum, subStepEnum); return ResponseEntity.status(HttpStatus.OK).body(subStepResponseDto); } - private void validMatchingOfMainStepAndSubStep(MainStepEnum mainStepEnum, SubStepEnum subStepEnum) { + private void validMatchingOfMainStepAndSubStep(MainStepEnum mainStepEnum, + SubStepEnum subStepEnum) { if (!mainStepEnum.isMatchingMainAndSub(subStepEnum)) { throw new BusinessException(ErrorCode.PROGRESS_SUB_MAIN_DO_NOT_MATCH); } diff --git a/boomerang/src/main/java/boomerang/progress/domain/MainStep.java b/boomerang/src/main/java/boomerang/progress/domain/MainStep.java index b9a770e3..d387c8ed 100644 --- a/boomerang/src/main/java/boomerang/progress/domain/MainStep.java +++ b/boomerang/src/main/java/boomerang/progress/domain/MainStep.java @@ -1,19 +1,29 @@ package boomerang.progress.domain; -import jakarta.persistence.*; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import java.util.List; +import java.util.Optional; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import java.util.List; -import java.util.Optional; - @Getter @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @EntityListeners(AuditingEntityListener.class) public class MainStep { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -48,12 +58,12 @@ public void registerSubStepList(List subStepList) { public Optional getSubStepByEnum(SubStepEnum subStepEnum) { return this.subStepList.stream() - .filter(subStep -> subStep.getSubStepEnum().equals(subStepEnum)) - .findFirst(); + .filter(subStep -> subStep.getSubStepEnum().equals(subStepEnum)) + .findFirst(); } public boolean isCompletion() { return this.subStepList.stream() - .allMatch(SubStep::isCompletion); + .allMatch(SubStep::isCompletion); } } diff --git a/boomerang/src/main/java/boomerang/progress/domain/MainStepEnum.java b/boomerang/src/main/java/boomerang/progress/domain/MainStepEnum.java index 40f5f0e4..d3c1888a 100644 --- a/boomerang/src/main/java/boomerang/progress/domain/MainStepEnum.java +++ b/boomerang/src/main/java/boomerang/progress/domain/MainStepEnum.java @@ -3,19 +3,29 @@ import boomerang.global.response.ErrorCode; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; - import java.util.List; public enum MainStepEnum { A1("전세권-설정-확인", List.of(SubStepEnum.A1_1)), - A2BC3("전세사기-피해자-신청", List.of(SubStepEnum.A2BC3_1, SubStepEnum.A2BC3_2, SubStepEnum.A2BC3_3, SubStepEnum.A2BC3_4, SubStepEnum.A2BC3_4, SubStepEnum.A2BC3_5, SubStepEnum.A2BC3_6, SubStepEnum.A2BC3_7, SubStepEnum.A2BC3_8, SubStepEnum.A2BC3_9, SubStepEnum.A2BC3_10, SubStepEnum.A2BC3_11)), + A2BC3("전세사기-피해자-신청", + List.of(SubStepEnum.A2BC3_1, SubStepEnum.A2BC3_2, SubStepEnum.A2BC3_3, SubStepEnum.A2BC3_4, + SubStepEnum.A2BC3_4, SubStepEnum.A2BC3_5, SubStepEnum.A2BC3_6, SubStepEnum.A2BC3_7, + SubStepEnum.A2BC3_8, SubStepEnum.A2BC3_9, SubStepEnum.A2BC3_10, SubStepEnum.A2BC3_11)), A3("경매-신청하는-방법", List.of(SubStepEnum.A3_1, SubStepEnum.A3_2)), - A4("배당-요구-신청", List.of(SubStepEnum.A4_1, SubStepEnum.A4_2, SubStepEnum.A4_3, SubStepEnum.A4_4, SubStepEnum.A4_5, SubStepEnum.A4_6)), + A4("배당-요구-신청", List.of(SubStepEnum.A4_1, SubStepEnum.A4_2, SubStepEnum.A4_3, SubStepEnum.A4_4, + SubStepEnum.A4_5, SubStepEnum.A4_6)), A5("경매-결과", List.of(SubStepEnum.A5_1, SubStepEnum.A5_2, SubStepEnum.A5_3)), - BC1("계약-해지-내용-증명", List.of(SubStepEnum.BC1_1, SubStepEnum.BC1_2, SubStepEnum.BC1_3, SubStepEnum.BC1_4, SubStepEnum.BC1_5)), - BC2("임차권-등기-명령", List.of(SubStepEnum.BC2_1, SubStepEnum.BC2_2, SubStepEnum.BC2_3, SubStepEnum.BC2_4, SubStepEnum.BC2_5, SubStepEnum.BC2_6, SubStepEnum.BC2_7)), - B4("지급-명령-신청-전세-보증금-반환-소송-집행권원-취득", List.of(SubStepEnum.B4_1, SubStepEnum.B4_2, SubStepEnum.B4_3, SubStepEnum.B4_4, SubStepEnum.B4_5)), - B5("압류-이후-경매-진행", List.of( SubStepEnum.B5_1, SubStepEnum.B5_2, SubStepEnum.B5_3, SubStepEnum.B5_4)), + BC1("계약-해지-내용-증명", + List.of(SubStepEnum.BC1_1, SubStepEnum.BC1_2, SubStepEnum.BC1_3, SubStepEnum.BC1_4, + SubStepEnum.BC1_5)), + BC2("임차권-등기-명령", + List.of(SubStepEnum.BC2_1, SubStepEnum.BC2_2, SubStepEnum.BC2_3, SubStepEnum.BC2_4, + SubStepEnum.BC2_5, SubStepEnum.BC2_6, SubStepEnum.BC2_7)), + B4("지급-명령-신청-전세-보증금-반환-소송-집행권원-취득", + List.of(SubStepEnum.B4_1, SubStepEnum.B4_2, SubStepEnum.B4_3, SubStepEnum.B4_4, + SubStepEnum.B4_5)), + B5("압류-이후-경매-진행", + List.of(SubStepEnum.B5_1, SubStepEnum.B5_2, SubStepEnum.B5_3, SubStepEnum.B5_4)), C4("보증-이행-청구", List.of(SubStepEnum.C4_1, SubStepEnum.C4_2)), C5("주택-명도-퇴거", List.of(SubStepEnum.C5_1, SubStepEnum.C5_2, SubStepEnum.C5_3)); diff --git a/boomerang/src/main/java/boomerang/progress/domain/Progress.java b/boomerang/src/main/java/boomerang/progress/domain/Progress.java index 4bb69cbb..dc4a3e14 100644 --- a/boomerang/src/main/java/boomerang/progress/domain/Progress.java +++ b/boomerang/src/main/java/boomerang/progress/domain/Progress.java @@ -1,15 +1,25 @@ package boomerang.progress.domain; import boomerang.member.domain.Member; -import jakarta.persistence.*; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import java.util.List; +import java.util.Optional; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import java.util.List; -import java.util.Optional; - @Getter @Entity @@ -42,8 +52,8 @@ public void registerMainStepList(List mainStepList) { public Optional getMainStepByEnum(MainStepEnum mainStepEnum) { return this.mainStepList.stream() - .filter(mainStep -> mainStep.getMainStepEnum().equals(mainStepEnum)) - .findFirst(); + .filter(mainStep -> mainStep.getMainStepEnum().equals(mainStepEnum)) + .findFirst(); } } diff --git a/boomerang/src/main/java/boomerang/progress/domain/ProgressType.java b/boomerang/src/main/java/boomerang/progress/domain/ProgressType.java index ce488a95..be7e3886 100644 --- a/boomerang/src/main/java/boomerang/progress/domain/ProgressType.java +++ b/boomerang/src/main/java/boomerang/progress/domain/ProgressType.java @@ -1,13 +1,19 @@ package boomerang.progress.domain; import com.fasterxml.jackson.annotation.JsonValue; - import java.util.List; public enum ProgressType { - A("A타입", "전세권 계약", List.of(MainStepEnum.A1,MainStepEnum.A2BC3,MainStepEnum.A3,MainStepEnum.A4,MainStepEnum.A5)), - B("B타입", "임대차 계약 / 보증 보험 X", List.of(MainStepEnum.BC1, MainStepEnum.BC2, MainStepEnum.A2BC3, MainStepEnum.B4, MainStepEnum.B5)), - C("C타입", "임대차 계약 / 보증 보험 O", List.of(MainStepEnum.BC1, MainStepEnum.BC2, MainStepEnum.A2BC3,MainStepEnum.C4,MainStepEnum.C5)),; + A("A타입", "전세권 계약", + List.of(MainStepEnum.A1, MainStepEnum.A2BC3, MainStepEnum.A3, MainStepEnum.A4, + MainStepEnum.A5)), + B("B타입", "임대차 계약 / 보증 보험 X", + List.of(MainStepEnum.BC1, MainStepEnum.BC2, MainStepEnum.A2BC3, MainStepEnum.B4, + MainStepEnum.B5)), + C("C타입", "임대차 계약 / 보증 보험 O", + List.of(MainStepEnum.BC1, MainStepEnum.BC2, MainStepEnum.A2BC3, MainStepEnum.C4, + MainStepEnum.C5)), + ; private final String typeName; private final String description; @@ -39,5 +45,4 @@ public String toString() { } - } \ No newline at end of file diff --git a/boomerang/src/main/java/boomerang/progress/domain/SubStep.java b/boomerang/src/main/java/boomerang/progress/domain/SubStep.java index e61f3cae..34c58669 100644 --- a/boomerang/src/main/java/boomerang/progress/domain/SubStep.java +++ b/boomerang/src/main/java/boomerang/progress/domain/SubStep.java @@ -1,6 +1,14 @@ package boomerang.progress.domain; -import jakarta.persistence.*; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -11,6 +19,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @EntityListeners(AuditingEntityListener.class) public class SubStep { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/boomerang/src/main/java/boomerang/progress/domain/SubStepInfo.java b/boomerang/src/main/java/boomerang/progress/domain/SubStepInfo.java index cf0cc9b3..48e754e2 100644 --- a/boomerang/src/main/java/boomerang/progress/domain/SubStepInfo.java +++ b/boomerang/src/main/java/boomerang/progress/domain/SubStepInfo.java @@ -1,12 +1,21 @@ package boomerang.progress.domain; import boomerang.progress.util.StringListConverter; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import java.util.ArrayList; +import java.util.List; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import java.util.*; @Getter @Entity diff --git a/boomerang/src/main/java/boomerang/progress/dto/MainStepResponseDto.java b/boomerang/src/main/java/boomerang/progress/dto/MainStepResponseDto.java index 47e7f9f6..588fc8dc 100644 --- a/boomerang/src/main/java/boomerang/progress/dto/MainStepResponseDto.java +++ b/boomerang/src/main/java/boomerang/progress/dto/MainStepResponseDto.java @@ -7,12 +7,11 @@ import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.List; - @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class MainStepResponseDto { + private String mainStepName; private Boolean completion; diff --git a/boomerang/src/main/java/boomerang/progress/dto/ProgressByMainResponseDto.java b/boomerang/src/main/java/boomerang/progress/dto/ProgressByMainResponseDto.java index 1ac76653..0059a7cd 100644 --- a/boomerang/src/main/java/boomerang/progress/dto/ProgressByMainResponseDto.java +++ b/boomerang/src/main/java/boomerang/progress/dto/ProgressByMainResponseDto.java @@ -6,25 +6,26 @@ import boomerang.progress.domain.ProgressType; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.Getter; - import java.util.List; +import lombok.Getter; @Getter @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class ProgressByMainResponseDto { + private ProgressType progressType; //유저의 타입 private MainStepEnum currentMainStep; //현재 메인 단계 private List mainStepList; //메인단계 리스트 private List subStepList; //서브리스트 - public ProgressByMainResponseDto(Progress progress, MainStep mainStep, List subStepList) { + public ProgressByMainResponseDto(Progress progress, MainStep mainStep, + List subStepList) { this.progressType = progress.getProgressType(); this.currentMainStep = mainStep.getMainStepEnum(); this.mainStepList = progress.getMainStepList() - .stream() - .map(MainStepResponseDto::new) - .toList(); + .stream() + .map(MainStepResponseDto::new) + .toList(); this.subStepList = subStepList; } } diff --git a/boomerang/src/main/java/boomerang/progress/dto/ProgressTypeRequestDto.java b/boomerang/src/main/java/boomerang/progress/dto/ProgressTypeRequestDto.java index b4c64e59..86b6b4c6 100644 --- a/boomerang/src/main/java/boomerang/progress/dto/ProgressTypeRequestDto.java +++ b/boomerang/src/main/java/boomerang/progress/dto/ProgressTypeRequestDto.java @@ -11,6 +11,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class ProgressTypeRequestDto { + private Boolean isInsured; //보험 가입 여부 private LeaseTypeEnum leaseType; //계약 종류 } diff --git a/boomerang/src/main/java/boomerang/progress/dto/ProgressTypeResponseDto.java b/boomerang/src/main/java/boomerang/progress/dto/ProgressTypeResponseDto.java index 9f81d6a0..53f979bd 100644 --- a/boomerang/src/main/java/boomerang/progress/dto/ProgressTypeResponseDto.java +++ b/boomerang/src/main/java/boomerang/progress/dto/ProgressTypeResponseDto.java @@ -9,6 +9,7 @@ @Getter @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class ProgressTypeResponseDto { + private ProgressType progressType; public ProgressTypeResponseDto(ProgressType progressType) { diff --git a/boomerang/src/main/java/boomerang/progress/dto/SubStepResponseDto.java b/boomerang/src/main/java/boomerang/progress/dto/SubStepResponseDto.java index 119e8ece..343bacec 100644 --- a/boomerang/src/main/java/boomerang/progress/dto/SubStepResponseDto.java +++ b/boomerang/src/main/java/boomerang/progress/dto/SubStepResponseDto.java @@ -9,11 +9,12 @@ @Getter @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class SubStepResponseDto { + private String name; //보험가입여부 private boolean completion; private String content; - public SubStepResponseDto(SubStep subStep,String content) { + public SubStepResponseDto(SubStep subStep, String content) { this.name = subStep.getName(); this.completion = subStep.isCompletion(); this.content = content; diff --git a/boomerang/src/main/java/boomerang/progress/repository/SubStepInfoRepository.java b/boomerang/src/main/java/boomerang/progress/repository/SubStepInfoRepository.java index 12e692bf..4f7a443e 100644 --- a/boomerang/src/main/java/boomerang/progress/repository/SubStepInfoRepository.java +++ b/boomerang/src/main/java/boomerang/progress/repository/SubStepInfoRepository.java @@ -3,10 +3,10 @@ import boomerang.progress.domain.SubStepEnum; import boomerang.progress.domain.SubStepInfo; -import org.springframework.data.jpa.repository.JpaRepository; - import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; public interface SubStepInfoRepository extends JpaRepository { + Optional findBySubStepEnum(SubStepEnum subStepEnum); } diff --git a/boomerang/src/main/java/boomerang/progress/service/ProgressService.java b/boomerang/src/main/java/boomerang/progress/service/ProgressService.java index bb38c3a7..db8bff2a 100644 --- a/boomerang/src/main/java/boomerang/progress/service/ProgressService.java +++ b/boomerang/src/main/java/boomerang/progress/service/ProgressService.java @@ -4,20 +4,24 @@ import boomerang.global.response.ErrorCode; import boomerang.member.domain.Member; import boomerang.member.service.MemberService; -import boomerang.progress.domain.*; +import boomerang.progress.domain.MainStep; +import boomerang.progress.domain.MainStepEnum; +import boomerang.progress.domain.Progress; +import boomerang.progress.domain.ProgressType; +import boomerang.progress.domain.SubStep; +import boomerang.progress.domain.SubStepEnum; import boomerang.progress.dto.ProgressByMainResponseDto; import boomerang.progress.dto.ProgressTypeRequestDto; import boomerang.progress.dto.SubStepResponseDto; import boomerang.progress.repository.ProgressRepository; import boomerang.progress.util.ProgressTypeResolver; import boomerang.progress.util.ProgressUtil; +import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.Optional; - @Service @RequiredArgsConstructor public class ProgressService { @@ -37,7 +41,8 @@ public ProgressType checkUserType(String email, ProgressTypeRequestDto progressT ProgressType progressType = ProgressTypeResolver.checkType(progressTypeRequestDto); - Progress savedProgress = progressRepository.save(ProgressUtil.makeProgress(progressType, member)); + Progress savedProgress = progressRepository.save( + ProgressUtil.makeProgress(progressType, member)); member.registerProgress(savedProgress); return progressType; @@ -47,7 +52,7 @@ public ProgressType checkUserType(String email, ProgressTypeRequestDto progressT public ProgressType getUserType(String email) { Member member = memberService.getMemberByEmail(email); return Optional.ofNullable(member.getProgressType()) - .orElseThrow(() -> new BusinessException(ErrorCode.PROGRESS_TYPE_NON_EXISTENT)); + .orElseThrow(() -> new BusinessException(ErrorCode.PROGRESS_TYPE_NON_EXISTENT)); } //유저의 진행도 전체 조회 @@ -64,7 +69,8 @@ public ProgressByMainResponseDto getProgressDetails(String email) { //특정 메인 단계만 조회 @Transactional(readOnly = true) - public ProgressByMainResponseDto getSubStepsByMainStep(String email, MainStepEnum mainStepEnum) { + public ProgressByMainResponseDto getSubStepsByMainStep(String email, + MainStepEnum mainStepEnum) { Member member = memberService.getMemberByEmail(email); Progress progress = getProgressByMember(member); @@ -77,8 +83,8 @@ public ProgressByMainResponseDto getSubStepsByMainStep(String email, MainStepEnu //특정 서브단계만 조회 @Transactional(readOnly = true) public SubStepResponseDto getSubStepStatus(String email, - MainStepEnum mainStepEnum, - SubStepEnum subStepEnum) { + MainStepEnum mainStepEnum, + SubStepEnum subStepEnum) { Member member = memberService.getMemberByEmail(email); Progress progress = getProgressByMember(member); @@ -91,7 +97,8 @@ public SubStepResponseDto getSubStepStatus(String email, //진행도 업데이트 @Transactional - public SubStepResponseDto completeProgress(String email, MainStepEnum mainStepEnum, SubStepEnum subStepEnum) { + public SubStepResponseDto completeProgress(String email, MainStepEnum mainStepEnum, + SubStepEnum subStepEnum) { Member member = memberService.getMemberByEmail(email); Progress progress = getProgressByMember(member); @@ -102,7 +109,8 @@ public SubStepResponseDto completeProgress(String email, MainStepEnum mainStepEn MainStep currentMainStep = getCurrentMainStep(progress); if (!currentMainStep.getMainStepEnum().equals(mainStepEnum)) { - throw new BusinessException(ErrorCode.PROGRESS_REQUEST_MAIN_STEP_IS_NOT_THE_CURRENT_STEP); + throw new BusinessException( + ErrorCode.PROGRESS_REQUEST_MAIN_STEP_IS_NOT_THE_CURRENT_STEP); } if (subStep.isCompletion()) { @@ -116,7 +124,8 @@ public SubStepResponseDto completeProgress(String email, MainStepEnum mainStepEn //진행도 완료 취소 @Transactional - public SubStepResponseDto revertProgressToIncomplete(String email, MainStepEnum mainStepEnum, SubStepEnum subStepEnum) { + public SubStepResponseDto revertProgressToIncomplete(String email, MainStepEnum mainStepEnum, + SubStepEnum subStepEnum) { Member member = memberService.getMemberByEmail(email); Progress progress = getProgressByMember(member); @@ -125,9 +134,9 @@ public SubStepResponseDto revertProgressToIncomplete(String email, MainStepEnum MainStep currentMainStep = getCurrentMainStep(progress); - if (!currentMainStep.getMainStepEnum().equals(mainStepEnum)) { - throw new BusinessException(ErrorCode.PROGRESS_REQUEST_MAIN_STEP_IS_NOT_THE_CURRENT_STEP); + throw new BusinessException( + ErrorCode.PROGRESS_REQUEST_MAIN_STEP_IS_NOT_THE_CURRENT_STEP); } if (!subStep.isCompletion()) { @@ -157,12 +166,12 @@ public MainStep getCurrentMainStep(Progress progress) { private MainStep getMainStepByEnum(Progress progress, MainStepEnum mainStepEnum) { return progress.getMainStepByEnum(mainStepEnum) - .orElseThrow(() -> new BusinessException(ErrorCode.PROGRESS_NOT_INCLUDED_MAIN)); + .orElseThrow(() -> new BusinessException(ErrorCode.PROGRESS_NOT_INCLUDED_MAIN)); } private SubStep getSubStepByEnum(MainStep mainStep, SubStepEnum subStepEnum) { return mainStep.getSubStepByEnum(subStepEnum) - .orElseThrow(() -> new BusinessException(ErrorCode.PROGRESS_NOT_INCLUDED_SUB)); + .orElseThrow(() -> new BusinessException(ErrorCode.PROGRESS_NOT_INCLUDED_SUB)); } private Progress getProgressByMember(Member member) { diff --git a/boomerang/src/main/java/boomerang/progress/service/SubStepInfoService.java b/boomerang/src/main/java/boomerang/progress/service/SubStepInfoService.java index cd66c9a9..6b599dd3 100644 --- a/boomerang/src/main/java/boomerang/progress/service/SubStepInfoService.java +++ b/boomerang/src/main/java/boomerang/progress/service/SubStepInfoService.java @@ -7,11 +7,10 @@ import boomerang.progress.domain.SubStepInfo; import boomerang.progress.dto.SubStepResponseDto; import boomerang.progress.repository.SubStepInfoRepository; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import java.util.List; - @Service @RequiredArgsConstructor public class SubStepInfoService { @@ -20,22 +19,23 @@ public class SubStepInfoService { public List getSubStepInfo(SubStepEnum subStepEnum) { SubStepInfo subStepInfo = subStepInfoRepository.findBySubStepEnum(subStepEnum) - .orElseThrow(() -> new BusinessException(ErrorCode.SUB_STEP_INFO_NOT_FOUND)); + .orElseThrow(() -> new BusinessException(ErrorCode.SUB_STEP_INFO_NOT_FOUND)); return subStepInfo.getInputs(); } public String getSubStepContent(SubStepEnum subStepEnum) { SubStepInfo subStepInfo = subStepInfoRepository.findBySubStepEnum(subStepEnum) - .orElseThrow(() -> new BusinessException(ErrorCode.SUB_STEP_INFO_NOT_FOUND)); + .orElseThrow(() -> new BusinessException(ErrorCode.SUB_STEP_INFO_NOT_FOUND)); return subStepInfo.getContent(); } public List getSubStepList(MainStep mainStep) { return mainStep.getSubStepList() - .stream() - .map(subStep -> new SubStepResponseDto(subStep, getSubStepContent(subStep.getSubStepEnum()))) - .toList(); + .stream() + .map(subStep -> new SubStepResponseDto(subStep, + getSubStepContent(subStep.getSubStepEnum()))) + .toList(); } } diff --git a/boomerang/src/main/java/boomerang/progress/util/ProgressTypeResolver.java b/boomerang/src/main/java/boomerang/progress/util/ProgressTypeResolver.java index 02c09277..29f14477 100644 --- a/boomerang/src/main/java/boomerang/progress/util/ProgressTypeResolver.java +++ b/boomerang/src/main/java/boomerang/progress/util/ProgressTypeResolver.java @@ -2,8 +2,8 @@ import boomerang.global.exception.BusinessException; import boomerang.global.response.ErrorCode; -import boomerang.progress.domain.ProgressType; import boomerang.progress.domain.LeaseTypeEnum; +import boomerang.progress.domain.ProgressType; import boomerang.progress.dto.ProgressTypeRequestDto; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -15,7 +15,6 @@ public static ProgressType checkType(ProgressTypeRequestDto progressTypeRequestD Boolean isMemberInsureds = progressTypeRequestDto.getIsInsured(); LeaseTypeEnum leaseType = progressTypeRequestDto.getLeaseType(); - if (!isMemberInsureds && leaseType.equals(LeaseTypeEnum.RENTAL)) { //보험가입 X, 임대차계약 return ProgressType.B; } diff --git a/boomerang/src/main/java/boomerang/progress/util/ProgressUtil.java b/boomerang/src/main/java/boomerang/progress/util/ProgressUtil.java index 244b47c4..4a39a764 100644 --- a/boomerang/src/main/java/boomerang/progress/util/ProgressUtil.java +++ b/boomerang/src/main/java/boomerang/progress/util/ProgressUtil.java @@ -2,32 +2,36 @@ import boomerang.member.domain.Member; -import boomerang.progress.domain.*; +import boomerang.progress.domain.MainStep; +import boomerang.progress.domain.MainStepEnum; +import boomerang.progress.domain.Progress; +import boomerang.progress.domain.ProgressType; +import boomerang.progress.domain.SubStep; +import java.util.List; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import java.util.List; - @NoArgsConstructor(access = AccessLevel.PRIVATE) public class ProgressUtil { + public static Progress makeProgress(ProgressType progressType, Member member) { List mainStepEnumList = progressType.getMainStepEnumList(); Progress progress = new Progress(member, progressType); List mainStepList = mainStepEnumList.stream() - .map( - mainStepEnum -> - { - MainStep mainStep = new MainStep(mainStepEnum, progress); - List subStepList = mainStepEnum.getSubStepEnumList() - .stream() - .map(subStepEnum -> new SubStep(mainStep, subStepEnum)).toList(); - - mainStep.registerSubStepList(subStepList); - - return mainStep; - }) - .toList(); + .map( + mainStepEnum -> + { + MainStep mainStep = new MainStep(mainStepEnum, progress); + List subStepList = mainStepEnum.getSubStepEnumList() + .stream() + .map(subStepEnum -> new SubStep(mainStep, subStepEnum)).toList(); + + mainStep.registerSubStepList(subStepList); + + return mainStep; + }) + .toList(); progress.registerMainStepList(mainStepList); diff --git a/boomerang/src/main/java/boomerang/progress/util/StringListConverter.java b/boomerang/src/main/java/boomerang/progress/util/StringListConverter.java index 326263d5..9b8c253e 100644 --- a/boomerang/src/main/java/boomerang/progress/util/StringListConverter.java +++ b/boomerang/src/main/java/boomerang/progress/util/StringListConverter.java @@ -8,17 +8,22 @@ @Converter public class StringListConverter implements AttributeConverter, String> { + private static final String SPLIT_CHAR = ","; @Override public String convertToDatabaseColumn(List list) { - if (list == null || list.isEmpty()) return ""; + if (list == null || list.isEmpty()) { + return ""; + } return String.join(SPLIT_CHAR, list); } @Override public List convertToEntityAttribute(String joined) { - if (joined == null || joined.isEmpty()) return new ArrayList<>(); + if (joined == null || joined.isEmpty()) { + return new ArrayList<>(); + } return new ArrayList<>(Arrays.asList(joined.split(SPLIT_CHAR))); } } diff --git a/boomerang/src/main/java/boomerang/template/controller/TemplateController.java b/boomerang/src/main/java/boomerang/template/controller/TemplateController.java index 205ca06e..839a4e4a 100644 --- a/boomerang/src/main/java/boomerang/template/controller/TemplateController.java +++ b/boomerang/src/main/java/boomerang/template/controller/TemplateController.java @@ -8,15 +8,23 @@ import boomerang.template.dto.TemplateRequestDto; import boomerang.template.dto.TemplateResponseDto; import boomerang.template.service.TemplateService; +import java.util.List; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/template") public class TemplateController { + private final TemplateService templateService; public TemplateController(TemplateService templateService) { @@ -27,42 +35,44 @@ public TemplateController(TemplateService templateService) { public ResponseEntity getAllTemplates() { List templateDomainList = templateService.getAllTemplateDomains(); return ResponseEntity.status(HttpStatus.OK) - .body(TemplateListResponseDto.of(templateDomainList)); + .body(TemplateListResponseDto.of(templateDomainList)); } @GetMapping("/{id}") public ResponseEntity getTemplateById(@PathVariable(name = "id") Long id) { TemplateDomain templateDomain = templateService.getTemplateDomainById(id); return ResponseEntity.status(HttpStatus.OK) - .body(TemplateResponseDto.of(templateDomain)); + .body(TemplateResponseDto.of(templateDomain)); } @PostMapping() public ResponseEntity createTemplate(@RequestBody TemplateRequestDto templateRequestDto) { templateService.createTemplateDomain(templateRequestDto.toTemplateDomain()); return ResponseEntity.status(HttpStatus.CREATED) - .build(); + .build(); } @PutMapping("/{id}") - public ResponseEntity updateTemplate(@PathVariable(name = "id") Long id, @RequestBody TemplateRequestDto templateRequestDto) { + public ResponseEntity updateTemplate(@PathVariable(name = "id") Long id, + @RequestBody TemplateRequestDto templateRequestDto) { templateService.updateTemplateDomain(templateRequestDto.toTemplateDomain(id)); return ResponseEntity.status(HttpStatus.CREATED) - .build(); + .build(); } @DeleteMapping("/{id}") public ResponseEntity deleteTemplate(@PathVariable(name = "id") Long id) { templateService.deleteTemplateDomain(id); return ResponseEntity.status(HttpStatus.OK) - .build(); + .build(); } // GlobalException Handler 에서 처리할 경우, // RequestBody에서 발생한 에러가 HttpMessageNotReadableException 로 Wrapping 이 되는 문제가 발생한다 // 때문에, 해당 에러로 Wrapping 되기 전 Controller 에서 Domain Error 를 처리해주었다 @ExceptionHandler(DomainValidationException.class) - public ResponseEntity handleOptionValidException(DomainValidationException e) { + public ResponseEntity handleOptionValidException( + DomainValidationException e) { System.out.println(e); return ResponseHelper.createErrorResponse(e.getErrorCode()); } diff --git a/boomerang/src/main/java/boomerang/template/domain/TemplateColumn1.java b/boomerang/src/main/java/boomerang/template/domain/TemplateColumn1.java index 744faf17..ddeed6fe 100644 --- a/boomerang/src/main/java/boomerang/template/domain/TemplateColumn1.java +++ b/boomerang/src/main/java/boomerang/template/domain/TemplateColumn1.java @@ -5,11 +5,11 @@ import com.fasterxml.jackson.annotation.JsonValue; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; - import java.util.Objects; @Embeddable public class TemplateColumn1 { + @Column(name = "template_column1") private String value; @@ -37,8 +37,12 @@ public String toString() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } TemplateColumn1 that = (TemplateColumn1) o; return Objects.equals(value, that.value); } diff --git a/boomerang/src/main/java/boomerang/template/domain/TemplateColumn2.java b/boomerang/src/main/java/boomerang/template/domain/TemplateColumn2.java index 30be3e71..73b0f5e9 100644 --- a/boomerang/src/main/java/boomerang/template/domain/TemplateColumn2.java +++ b/boomerang/src/main/java/boomerang/template/domain/TemplateColumn2.java @@ -5,11 +5,11 @@ import com.fasterxml.jackson.annotation.JsonValue; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; - import java.util.Objects; @Embeddable public class TemplateColumn2 { + @Column(name = "template_column2") private String value; @@ -37,8 +37,12 @@ public String toString() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } TemplateColumn2 that = (TemplateColumn2) o; return Objects.equals(value, that.value); } diff --git a/boomerang/src/main/java/boomerang/template/domain/TemplateDomain.java b/boomerang/src/main/java/boomerang/template/domain/TemplateDomain.java index 7681ab14..4d09a8e0 100644 --- a/boomerang/src/main/java/boomerang/template/domain/TemplateDomain.java +++ b/boomerang/src/main/java/boomerang/template/domain/TemplateDomain.java @@ -1,19 +1,24 @@ package boomerang.template.domain; -import jakarta.persistence.*; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.util.Objects; import lombok.Builder; import lombok.Getter; import lombok.Setter; import org.hibernate.Hibernate; -import java.util.Objects; - @Getter @Setter @Entity @Builder @Table(name = "template") public class TemplateDomain { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -27,7 +32,8 @@ public class TemplateDomain { public TemplateDomain() { } - public TemplateDomain(Long id, TemplateColumn1 templateColumn1, TemplateColumn2 templateColumn2) { + public TemplateDomain(Long id, TemplateColumn1 templateColumn1, + TemplateColumn2 templateColumn2) { this.id = id; this.templateColumn1 = templateColumn1; this.templateColumn2 = templateColumn2; @@ -35,9 +41,12 @@ public TemplateDomain(Long id, TemplateColumn1 templateColumn1, TemplateColumn2 @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) + if (this == o) { + return true; + } + if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) { return false; + } TemplateDomain item = (TemplateDomain) o; return Objects.equals(id, item.id); } diff --git a/boomerang/src/main/java/boomerang/template/dto/TemplateListNeedItem.java b/boomerang/src/main/java/boomerang/template/dto/TemplateListNeedItem.java index 30c9c47f..4606d59a 100644 --- a/boomerang/src/main/java/boomerang/template/dto/TemplateListNeedItem.java +++ b/boomerang/src/main/java/boomerang/template/dto/TemplateListNeedItem.java @@ -3,12 +3,11 @@ import boomerang.template.domain.TemplateColumn1; import boomerang.template.domain.TemplateColumn2; import boomerang.template.domain.TemplateDomain; +import java.util.List; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; -import java.util.List; - /* 상황에 따라서는 List 로 담고 싶은 ResponseDto 와 기존의 ResponseDto의 형태가 조금 달라지는 경우가 있다 @@ -34,6 +33,7 @@ @Builder @EqualsAndHashCode public class TemplateListNeedItem { + // page와 같은 추가적인 정보를 담는 필드 private String val; private List ItemList; @@ -49,19 +49,20 @@ public TemplateListNeedItem(String val, List ItemList) { */ public static TemplateListNeedItem of(List templateDomainList) { List templateResponseDtoList = templateDomainList.stream() - .map(Item::of) - .toList(); + .map(Item::of) + .toList(); return TemplateListNeedItem.builder() - .val("some_value") // 필요에 따라 값 설정 - .ItemList(templateResponseDtoList) - .build(); + .val("some_value") // 필요에 따라 값 설정 + .ItemList(templateResponseDtoList) + .build(); } @Getter @Builder public static class Item { + private TemplateColumn1 templateColumn1; private TemplateColumn2 templateColumn2; @@ -76,9 +77,9 @@ public Item(TemplateColumn1 templateColumn1, TemplateColumn2 templateColumn2) { */ public static Item of(TemplateDomain templateDomain) { return Item.builder() - .templateColumn1(templateDomain.getTemplateColumn1()) - .templateColumn2(templateDomain.getTemplateColumn2()) - .build(); + .templateColumn1(templateDomain.getTemplateColumn1()) + .templateColumn2(templateDomain.getTemplateColumn2()) + .build(); } } } diff --git a/boomerang/src/main/java/boomerang/template/dto/TemplateListResponseDto.java b/boomerang/src/main/java/boomerang/template/dto/TemplateListResponseDto.java index 527ce7f7..413ab855 100644 --- a/boomerang/src/main/java/boomerang/template/dto/TemplateListResponseDto.java +++ b/boomerang/src/main/java/boomerang/template/dto/TemplateListResponseDto.java @@ -1,12 +1,11 @@ package boomerang.template.dto; import boomerang.template.domain.TemplateDomain; +import java.util.List; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; -import java.util.List; - /* 상황에 따라서는 List 로 담고 싶은 ResponseDto 와 기존의 ResponseDto의 형태가 조금 달라지는 경우가 있다 @@ -33,6 +32,7 @@ @Builder @EqualsAndHashCode public class TemplateListResponseDto { + // page와 같은 추가적인 정보를 담는 필드 private String val; private List templateResponseDtoList; @@ -48,12 +48,12 @@ public TemplateListResponseDto(String val, List templateRes */ public static TemplateListResponseDto of(List templateDomainList) { List templateResponseDtoList = templateDomainList.stream() - .map(TemplateResponseDto::of) - .toList(); + .map(TemplateResponseDto::of) + .toList(); return TemplateListResponseDto.builder() - .val("some_value") // 필요에 따라 값 설정 - .templateResponseDtoList(templateResponseDtoList) - .build(); + .val("some_value") // 필요에 따라 값 설정 + .templateResponseDtoList(templateResponseDtoList) + .build(); } } diff --git a/boomerang/src/main/java/boomerang/template/dto/TemplateRequestDto.java b/boomerang/src/main/java/boomerang/template/dto/TemplateRequestDto.java index ce32d87d..b2ca2711 100644 --- a/boomerang/src/main/java/boomerang/template/dto/TemplateRequestDto.java +++ b/boomerang/src/main/java/boomerang/template/dto/TemplateRequestDto.java @@ -10,6 +10,7 @@ @EqualsAndHashCode //@NoArgsConstructor(access = AccessLevel.PROTECTED) public class TemplateRequestDto { + private TemplateColumn1 templateColumn1; private TemplateColumn2 templateColumn2; @@ -22,16 +23,16 @@ public TemplateRequestDto(TemplateColumn1 templateColumn1, TemplateColumn2 templ // TemplateCreateServiceDto로 변환하는 메서드 public TemplateDomain toTemplateDomain() { return TemplateDomain.builder() - .templateColumn1(templateColumn1) - .templateColumn2(templateColumn2) - .build(); + .templateColumn1(templateColumn1) + .templateColumn2(templateColumn2) + .build(); } public TemplateDomain toTemplateDomain(Long id) { return TemplateDomain.builder() - .id(id) - .templateColumn1(templateColumn1) - .templateColumn2(templateColumn2) - .build(); + .id(id) + .templateColumn1(templateColumn1) + .templateColumn2(templateColumn2) + .build(); } } diff --git a/boomerang/src/main/java/boomerang/template/dto/TemplateResponseDto.java b/boomerang/src/main/java/boomerang/template/dto/TemplateResponseDto.java index a22d10f0..dcdb7ba5 100644 --- a/boomerang/src/main/java/boomerang/template/dto/TemplateResponseDto.java +++ b/boomerang/src/main/java/boomerang/template/dto/TemplateResponseDto.java @@ -9,6 +9,7 @@ @Getter @Builder public class TemplateResponseDto { + private TemplateColumn1 templateColumn1; private TemplateColumn2 templateColumn2; @@ -27,8 +28,8 @@ public TemplateResponseDto(TemplateColumn1 templateColumn1, TemplateColumn2 temp */ public static TemplateResponseDto of(TemplateDomain templateDomain) { return TemplateResponseDto.builder() - .templateColumn1(templateDomain.getTemplateColumn1()) - .templateColumn2(templateDomain.getTemplateColumn2()) - .build(); + .templateColumn1(templateDomain.getTemplateColumn1()) + .templateColumn2(templateDomain.getTemplateColumn2()) + .build(); } } diff --git a/boomerang/src/main/java/boomerang/template/dto/TemplateServiceDto.java b/boomerang/src/main/java/boomerang/template/dto/TemplateServiceDto.java index 23c04986..e31e8f6e 100644 --- a/boomerang/src/main/java/boomerang/template/dto/TemplateServiceDto.java +++ b/boomerang/src/main/java/boomerang/template/dto/TemplateServiceDto.java @@ -9,12 +9,14 @@ // 일반적인 경우 Request 에서 바로 Domain으로 변환 @Getter public class TemplateServiceDto { + private Long id; private TemplateColumn1 templateColumn1; private TemplateColumn2 templateColumn2; // 생성자 - public TemplateServiceDto(Long id, TemplateColumn1 templateColumn1, TemplateColumn2 templateColumn2) { + public TemplateServiceDto(Long id, TemplateColumn1 templateColumn1, + TemplateColumn2 templateColumn2) { this.id = id; this.templateColumn1 = templateColumn1; this.templateColumn2 = templateColumn2; diff --git a/boomerang/src/main/java/boomerang/template/exception/TemplateNotFoundException.java b/boomerang/src/main/java/boomerang/template/exception/TemplateNotFoundException.java index 18392d59..3e7a72d9 100644 --- a/boomerang/src/main/java/boomerang/template/exception/TemplateNotFoundException.java +++ b/boomerang/src/main/java/boomerang/template/exception/TemplateNotFoundException.java @@ -4,6 +4,7 @@ import boomerang.global.response.ErrorCode; public class TemplateNotFoundException extends BusinessException { + public TemplateNotFoundException() { super(ErrorCode.TEMPLATE_NOT_FOUND_ERROR); } diff --git a/boomerang/src/main/java/boomerang/template/exception/TemplateValidException.java b/boomerang/src/main/java/boomerang/template/exception/TemplateValidException.java index f3056ddb..a255cc3e 100644 --- a/boomerang/src/main/java/boomerang/template/exception/TemplateValidException.java +++ b/boomerang/src/main/java/boomerang/template/exception/TemplateValidException.java @@ -4,6 +4,7 @@ import boomerang.global.response.ErrorCode; public class TemplateValidException extends DomainValidationException { + public TemplateValidException(ErrorCode errorCode) { super(errorCode); } diff --git a/boomerang/src/main/java/boomerang/template/repository/TemplateRepository.java b/boomerang/src/main/java/boomerang/template/repository/TemplateRepository.java index b48bf4dd..98a98fbb 100644 --- a/boomerang/src/main/java/boomerang/template/repository/TemplateRepository.java +++ b/boomerang/src/main/java/boomerang/template/repository/TemplateRepository.java @@ -4,5 +4,6 @@ import boomerang.template.domain.TemplateDomain; public interface TemplateRepository extends MyCrudRepository { + boolean existsById(Long id); } diff --git a/boomerang/src/main/java/boomerang/template/service/TemplateService.java b/boomerang/src/main/java/boomerang/template/service/TemplateService.java index 6b67c289..d098e452 100644 --- a/boomerang/src/main/java/boomerang/template/service/TemplateService.java +++ b/boomerang/src/main/java/boomerang/template/service/TemplateService.java @@ -3,12 +3,12 @@ import boomerang.template.domain.TemplateDomain; import boomerang.template.exception.TemplateNotFoundException; import boomerang.template.repository.TemplateRepository; -import org.springframework.stereotype.Service; - import java.util.List; +import org.springframework.stereotype.Service; @Service public class TemplateService { + private final TemplateRepository templateRepository; public TemplateService(TemplateRepository templateRepository) { @@ -21,7 +21,7 @@ public List getAllTemplateDomains() { public TemplateDomain getTemplateDomainById(Long id) { return templateRepository.findById(id) - .orElseThrow(TemplateNotFoundException::new); + .orElseThrow(TemplateNotFoundException::new); } public TemplateDomain createTemplateDomain(TemplateDomain templateDomain) { diff --git a/boomerang/src/main/resources/badWordsFile.json b/boomerang/src/main/resources/badWordsFile.json index 3d4c712f..41e3fa8e 100644 --- a/boomerang/src/main/resources/badWordsFile.json +++ b/boomerang/src/main/resources/badWordsFile.json @@ -1 +1,1109 @@ -["새끼", "쌔끼", "후장뚫어18세키", "dogbaby", "18ㅅㅐㄲㅣ", "18ㅅㅔㅋㅣ", "yadong", "ㅌㅓㄹㅐㄱㅣ", "따아알따아리", "막대쑤셔줘?", "보지머리박기", "보지에자지껴", "보지에자지너", "보지핧아줄까", "여자ㄸㅏ먹기", "여자ㄸㅏ묵기", "조개마셔줘?", "조개벌려조?", "조개쑤셔줘?", "조개핧아줘?", "터래기터래기", "혀로보지핧기", "18nom", "18num", "18ㅅㅐ끼", "18ㅅㅔ키", "18세ㅋㅣ", "sex하자", "가슴조물락", "가슴주물럭", "가슴쪼물딱", "가슴쪼물락", "개씨발자슥", "개애거얼래", "개에거얼래", "개젓가튼넘", "개후라들놈", "개후라새끼", "걸레같은년", "괴에가튼?", "따먹어야지", "따아알따리", "떠어라아이", "또오라아이", "막대핧아줘", "미친씨부랄", "바주카자지", "버따리자지", "버어어지이", "버지따먹기", "버지물마셔", "버짓물마셔", "벌창같은년", "보지따먹기", "보지물마셔", "보지벌리자", "보지쥐어짜", "보지털뽑아", "보지틀래기", "보지핧아줘", "보짓물마셔", "빠아구우리", "사까아시이", "쉬이이이이", "쓰브랄쉽세", "야dong", "어미따먹자", "어미쑤시자", "여자따먹기", "여자따묵기", "유발조물락", "유방주물럭", "유방쪼물딱", "유방쪼물럭", "유우우방것", "자지빨아줘", "자지쓰레기", "자지핧아줘", "잠지물마셔", "잠짓물마셔", "젓가튼쉐이", "조개넓은년", "조개따조?", "조오우까튼", "좃만한쉐이", "좋은말같은새끼", "좋은말만한새끼", "쳐쑤셔박어", "촌씨브라리", "촌씨브랑이", "촌씨브랭이", "크리토리스", "클리토리스", "sibal", "fuck", "shit", "18새끼", "18세키", "boji", "bozi", "jaji", "jazi", "jot같", "sex해", "zaji", "zazi", "ㅅㅐㄲㅣ", "ㅆㅣㅂㅏ", "ㅆㅣ팍넘", "ㅇㅍㅊㅌ", "가슴만져", "가슴빨아", "가슴빨어", "가슴핧아", "가슴핧어", "강간한다", "같은새끼", "개가튼년", "개가튼뇬", "개같은년", "개거얼래", "개거얼레", "개념빠가", "개보지년", "개쓰래기", "개쓰레기", "개씁자지", "개씨발넘", "개애걸래", "개에가튼", "개에걸래", "개작두넘", "개작두년", "개잡지랄", "개저가튼", "개지랄넘", "개지랄놈", "개후라년", "걔잡지랄", "거지같은", "걸레보지", "걸레핀년", "게에가튼", "게지랄놈", "그나물에", "나쁜새끼", "난자마셔", "난자먹어", "난자핧아", "내꺼빨아", "내꺼핧아", "너거애비", "노무노무", "누나강간", "니씨브랄", "니아범?", "니할애비", "대애가리", "대에가리", "더어엉신", "더러운년", "덜은새끼", "돌은새끼", "동생강간", "뒤이치기", "뒤져야지", "뒤지고싶", "뒷잇치기", "드으응신", "따먹는다", "따먹었어", "따먹었지", "따먹을까", "따알따리", "떠어라이", "또오라이", "띠부우울", "띠이바알", "띠이버얼", "띠이이발", "띠이이벌", "맛없는년", "맛이간년", "미시친발", "미친구녕", "미친구멍", "미친새끼", "미친쉐이", "버어어지", "버어지이", "버지구녕", "버지구멍", "버지냄새", "버지뚫어", "버지뜨더", "버지벌려", "버지벌료", "버지빨아", "버지빨어", "버지썰어", "버지쑤셔", "버지핧아", "병신세리", "병신셰리", "병신씨발", "보지구녕", "보지구멍", "보지뚫어", "보지뜨더", "보지박어", "보지벌려", "보지벌료", "보지벌리", "보지보지", "보지빨아", "보지빨어", "보지자지", "보지정액", "보지찌져", "보지찢어", "보지털어", "보지핧아", "보지핧어", "뷰우웅신", "뷰웅시인", "빙신쉐이", "빠가야로", "빠가십새", "빠가씹새", "빠아구리", "빠아아라", "사까시이", "사까아시", "새77ㅣ", "성교하자", "섹스하자", "쉬이이이", "시미발친", "시미친발", "시바라지", "시바시바", "시박색히", "시박쉑히", "좋은말새끼", "시방색희", "시방쉑희", "시새발끼", "시입세에", "시친발미", "시팍새끼", "시팔새끼", "십탱구리", "십탱굴이", "십팔새끼", "싸가지없", "쌍쌍보지", "쓰래기같", "쓰레기새", "쓰바새끼", "씨가랭넘", "씨가랭년", "씨가랭놈", "씨박색희", "씨박색히", "씨박쉑히", "씨발병신", "씨뱅가리", "씨벌쉐이", "씨븡새끼", "씨새발끼", "씨입새에", "씨입세에", "씨팍새끼", "씨팍세끼", "씨퐁보지", "씨퐁자지", "씹탱굴이", "아아가리", "아오좋은말", "아오시바", "애미보지", "애미씨뱅", "애미자지", "애미잡년", "애미좃물", "어미강간", "엿먹어라", "오르가즘", "왕털버지", "왕털보지", "왕털자지", "왕털잠지", "유두빨어", "유두핧어", "유방만져", "유방빨아", "유방핧아", "유방핧어", "유우까압", "자기핧아", "자지구녕", "자지구멍", "자지꽂아", "자지넣자", "자지뜨더", "자지뜯어", "자지박어", "자지빨아", "자지빨어", "자지쑤셔", "자지정개", "자지짤라", "자지핧아", "자지핧어", "작은보지", "잠지뚫어", "젓대가리", "젓물냄새", "정액마셔", "정액먹어", "정액발사", "정액핧아", "정자마셔", "정자먹어", "정자핧아", "조개보지", "조개속물", "조오가튼", "조오까튼", "조오오조", "조오온니", "조오올라", "조온마니", "조옴마니", "조우까튼", "좀쓰레기", "좁빠라라", "좃가튼뇬", "좃대가리", "좃마무리", "좃만한것", "좃물냄새", "좃빠구리", "좃빠라라", "좋은말같은놈", "좋은말만한년", "좋은말만한놈", "좋만한것", "주둥아리", "지이라알", "쪼다새끼", "창녀버지", "창년벼지", "캐럿닷컴", "항문수셔", "항문쑤셔", "허버리년", "허벌보지", "허벌자식", "허벌자지", "헐렁보지", "호로새끼", "호로자슥", "호로자식", "호루자슥", "후라덜넘", "후우자앙", "후장꽂아", "후장뚫어", "18년", "18놈", "d쥐고", "d지고", "me췬", "me친", "me틴", "mi친", "mi틴", "ya동", "ㅁㅣ췬", "ㅂㅁㄱ", "ㅅ.ㅂ", "ㅅㄲ네", "ㅅㄲ들", "ㅅㅡ루", "ㅆㄹㄱ", "ㅆㅣ8", "ㅆㅣ댕", "ㅆㅣ뎅", "ㅆㅣ바", "ㅆㅣ발", "ㅇㅒ쁜", "좋은말.ㄴ", "좋은말ㅏ위", "ㅉ질한", "ㄱㅅㄲ", "개.웃", "개가튼", "개같이", "개걸래", "개걸레", "개고치", "개너미", "개라슥", "개마이", "개보지", "개부달", "개부랄", "개불랄", "개붕알", "개새기", "개새끼", "개색뀌", "개색휘", "개샛기", "개소리", "개쉐뀌", "개씁년", "개씁블", "개씨발", "개씨블", "개아기", "개자식", "개자지", "개잡년", "개저씨", "개저엇", "개지랄", "개후라", "걔잡년", "거시기", "걸래년", "걸레년", "게가튼", "게부럴", "게저엇", "계새끼", "괘새끼", "괴가튼", "굿보지", "김대중", "김치녀", "깨쌔끼", "나빼썅", "내미랄", "내미럴", "내버지", "내씨발", "내자지", "내잠지", "내조지", "노네들", "노알라", "노무현", "느그매", "니기미", "니미기", "니미랄", "니미럴", "니아범", "니애미", "니애비", "닝기리", "닥쳐라", "닥치세", "달달이", "달딸이", "닳은년", "대가리", "대음순", "더엉신", "돈새끼", "돌았네", "돌으년", "뒤져라", "뒤져버", "뒤져야", "뒤져요", "뒤지겠", "뒤지길", "뒤진다", "뒤치기", "뒷치기", "드응신", "디져라", "디지고", "따먹기", "따먹어", "따먹자", "딸달이", "딸딸이", "떠라이", "또라이", "또라인", "똘아이", "띠발뇬", "띠부울", "띠브울", "띠블넘", "띠이발", "띠이벌", "막간년", "맛간년", "미쳣네", "미쳤나", "미쳤니", "미치인", "미친ㅋ", "미친개", "미친넘", "미친년", "미친놈", "미친눔", "미친새", "미친색", "미티넘", "미틴것", "방점뱅", "백보지", "버어지", "버지털", "버짓물", "보지녀", "보지물", "보지털", "보짓물", "뷰웅신", "빠가냐", "빠간가", "빠가새", "빠가니", "빠구리", "빠구울", "빠굴이", "빠아가", "빡새끼", "빨치산", "사까쉬", "사까시", "사새끼", "새ㄲㅣ", "새끼라", "새끼야", "성교해", "성폭행", "세엑스", "세엑쓰", "섹스해", "소음순", "쉬방새", "쉬이바", "쉬이이", "쉽알넘", "슈ㅣ발", "슈우벌", "슨상님", "시댕이", "시바류", "시바알", "시바앙", "시발년", "시발놈", "시방새", "시벌탱", "시볼탱", "시부럴", "시부렬", "시부울", "시뷰럴", "시뷰렬", "시이발", "시입세", "시키가", "시팔넘", "시팔년", "시팔놈", "십버지", "십부랄", "십부럴", "십세리", "십세이", "십셰리", "십쉐끼", "십자석", "십자슥", "십지랄", "십창녀", "십팔넘", "싸가지", "싸물어", "쌍보지", "쌔엑스", "쎄엑스", "씨ㅂㅏ", "씨댕이", "씨바라", "씨바알", "씨발년", "씨발롬", "씨방새", "씨방세", "씨버럼", "씨벌년", "씨벌탱", "씨볼탱", "씨부랄", "씨부럴", "씨부렬", "씨불알", "씨뷰럴", "씨뷰렬", "씨브럴", "씨블년", "씨빠빠", "씨섹끼", "씨이발", "씨입새", "씨입세", "씨파넘", "씨팍넘", "씨퐁넘", "씨퐁뇬", "씹미랄", "씹버지", "씹보지", "씹부랄", "씹브랄", "씹빵구", "씹뻐럴", "씹뽀지", "씹새끼", "씹쉐뀌", "씹쌔끼", "씹자석", "씹자슥", "씹자지", "씹지랄", "씹창녀", "씹탱이", "씹팔넘", "아가리", "애미랄", "애애무", "애에무", "애에미", "애에비", "에애무", "에에무", "에에미", "에에비", "여어엄", "여엄병", "염병할", "엿이나", "왕버지", "왕자지", "왕잠지", "왜저럼", "유우깝", "유우방", "은새끼", "이새끼", "자압것", "자지털", "잠지털", "젓같내", "젓냄새", "젓만이", "정액짜", "젖탱이", "졌같은", "조가튼", "조오또", "조오웃", "조오지", "조온나", "조온니", "조온만", "조올라", "조옷만", "족같내", "족까내", "존.나", "존ㄴ나", "존나아", "존마니", "좀마니", "좃간년", "좃까리", "좃깟네", "좃냄새", "좃만아", "좃만이", "좃보지", "좃부랄", "좃빠네", "좆까라", "좆만아", "좆먹어", "좆빨아", "좆새끼", "좋오웃", "죠온나", "주글년", "주길년", "주둥이", "줬같은", "지껄이", "ㅈ1랄", "지이랄", "쪽바리", "찝째끼", "쳐받는", "쳐발라", "친구년", "친노마", "큰보지", "페니스", "허벌년", "허벌레", "허어벌", "호냥년", "호로자", "호로잡", "화낭년", "화냥년", "후.려", "후라덜", "후우장", "미칭럼", "느금마", "ㅈ같네", "ㅁㅊ", "ㅁ친", "ㅂㄹ", "ㅂㅊ", "ㅂ크", "좋은말", "ㅅㅍ", "ㅅㅋ", "ㅅ루", "ㅅ발", "ㅆㄺ", "ㅆㅂ", "ㅆㅣ", "ㅈㄴ", "ㅈㄹ", "ㅈ리", "강간", "개간", "개같", "개넷", "개년", "개놈", "개독", "개련", "개섹", "개셈", "개젓", "개좆", "개쩌", "게젓", "골빈", "공알", "구씹", "귀두", "꼭지", "년놈", "뇌텅", "뇨온", "늬믜", "늬미", "니년", "니믜", "니미", "닥쳐", "대갈", "돈년", "뒈져", "뒤졌", "뒤질", "등신", "디졌", "디질", "딴년", "띠바", "띠발", "띠벌", "띠벨", "띠불", "띠블", "런년", "럼들", "롬들", "맘충", "머갈", "믜칀", "믜친", "미띤", "미췬", "미칀", "미친", "미틴", "및힌", "발놈", "벌창", "벵신", "별창", "병닥", "병딱", "병맛", "병신", "병크", "보지", "봉알", "부랄", "불알", "붕신", "붕알", "븅신", "브랄", "빙띤", "빙신", "빠굴", "빠네", "빠라", "빠큐", "빻았", "빻은", "뻐규", "뻐큐", "뻑유", "뻑큐", "뻨큐", "뼈큐", "뽀지", "상년", "새끼", "새퀴", "새킈", "새키", "색희", "색히", "샊기", "샊히", "샹년", "섀키", "성괴", "성교", "세끼", "세키", "섹끼", "섹스", "쇅끼", "쇡끼", "쉐끼", "쉬박", "쉬발", "쉬버", "쉬빡", "쉬탱", "쉬팍", "쉬펄", "쉽세", "슈발", "슈벌", "스벌", "싑창", "시바", "시파", "좋은말", "시벌", "시빡", "시빨", "시탱", "시팍", "시팔", "시펄", "십녀", "십새", "십세", "십창", "십탱", "십팔", "싹스", "쌍년", "쌍놈", "쌔끼", "쌕스", "쌕쓰", "썅놈", "썅년", "썌끼", "쎄끼", "쎄리", "쎅스", "쎅쓰", "쒸8", "쒸댕", "쒸발", "쒸팔", "쒸펄", "쓰댕", "쓰뎅", "쓰렉", "쓰루", "쓰바", "쓰발", "쓰벌", "쓰벨", "쓰파", "씌8", "씌댕", "씌뎅", "씌발", "씌벨", "씌팔", "씝창", "씨8", "씨걸", "씨댕", "씨뎅", "씨바", "씨발", "씨벌", "씨벨", "씨블", "씨븡", "씨비", "씨빡", "씨빨", "씨뻘", "씨입", "씨팍", "씨팔", "씨퐁", "씹귀", "씹년", "씹덕", "씹못", "씹물", "씹새", "씹세", "씹쌔", "씹창", "씹치", "씹탱", "씹팔", "씹할", "아닥", "애무", "애미", "애비", "앰창", "야동", "엄창", "에무", "에미", "에비", "엠생", "엠창", "염병", "염뵹", "엿같", "옘병", "외퀴", "요년", "유깝", "유두", "유방", "육갑", "은년", "음경", "이년", "자위", "자지", "잠지", "짬지", "잡것", "잡년", "잡놈", "저년", "저엇", "저엊", "적까", "절라", "점물", "젓까", "젓떠", "젓물", "젓밥", "젖같", "젖까", "젗같", "젼나", "젼낰", "졏같", "조깟", "조또", "조온", "족까", "존귀", "존귘", "존나", "존낙", "존내", "존니", "존똑", "존맛", "존멋", "존버", "존싫", "존쎄", "존쎼", "존예", "존웃", "존잘", "존잼", "존좋", "존트", "졸귀", "졸귘", "졸라", "졸맛", "졸멋", "졸싫", "졸예", "졸웃", "졸잼", "졸좋", "좀물", "좁밥", "좃까", "좃넘", "좃도", "좃또", "좃물", "좃털", "종나", "좆까", "좆나", "좆년", "좆도", "좆물", "좆밥", "좆털", "좋만", "죠낸", "죤나", "죤내", "죵나", "쥐랄", "쥰나", "쥰내", "쥰니", "쥰트", "즤랄", "지랄", "지럴", "지롤", "지뢀", "지뢰", "짱깨", "짱께", "쪼녜", "쪼다", "쪽발", "쫓같", "쬰잘", "창남", "창녀", "창년", "창놈", "처먹", "첫빠", "쳐마", "쳐먹", "취ㅈ", "취좃", "친년", "친놈", "파친", "펑글", "항문", "허벌", "호로", "후려", "후장", "꽃휴", "ㅂㅅ", "걔섀", "느금", "늑음", "ㅈ같", "ㅄ", "凸", "뇬", "썅", "씹", "좃", "좋은말", "좇", "죶", "쫂", "쬲","바보","멍청이"] \ No newline at end of file +[ + "새끼", + "쌔끼", + "후장뚫어18세키", + "dogbaby", + "18ㅅㅐㄲㅣ", + "18ㅅㅔㅋㅣ", + "yadong", + "ㅌㅓㄹㅐㄱㅣ", + "따아알따아리", + "막대쑤셔줘?", + "보지머리박기", + "보지에자지껴", + "보지에자지너", + "보지핧아줄까", + "여자ㄸㅏ먹기", + "여자ㄸㅏ묵기", + "조개마셔줘?", + "조개벌려조?", + "조개쑤셔줘?", + "조개핧아줘?", + "터래기터래기", + "혀로보지핧기", + "18nom", + "18num", + "18ㅅㅐ끼", + "18ㅅㅔ키", + "18세ㅋㅣ", + "sex하자", + "가슴조물락", + "가슴주물럭", + "가슴쪼물딱", + "가슴쪼물락", + "개씨발자슥", + "개애거얼래", + "개에거얼래", + "개젓가튼넘", + "개후라들놈", + "개후라새끼", + "걸레같은년", + "괴에가튼?", + "따먹어야지", + "따아알따리", + "떠어라아이", + "또오라아이", + "막대핧아줘", + "미친씨부랄", + "바주카자지", + "버따리자지", + "버어어지이", + "버지따먹기", + "버지물마셔", + "버짓물마셔", + "벌창같은년", + "보지따먹기", + "보지물마셔", + "보지벌리자", + "보지쥐어짜", + "보지털뽑아", + "보지틀래기", + "보지핧아줘", + "보짓물마셔", + "빠아구우리", + "사까아시이", + "쉬이이이이", + "쓰브랄쉽세", + "야dong", + "어미따먹자", + "어미쑤시자", + "여자따먹기", + "여자따묵기", + "유발조물락", + "유방주물럭", + "유방쪼물딱", + "유방쪼물럭", + "유우우방것", + "자지빨아줘", + "자지쓰레기", + "자지핧아줘", + "잠지물마셔", + "잠짓물마셔", + "젓가튼쉐이", + "조개넓은년", + "조개따조?", + "조오우까튼", + "좃만한쉐이", + "좋은말같은새끼", + "좋은말만한새끼", + "쳐쑤셔박어", + "촌씨브라리", + "촌씨브랑이", + "촌씨브랭이", + "크리토리스", + "클리토리스", + "sibal", + "fuck", + "shit", + "18새끼", + "18세키", + "boji", + "bozi", + "jaji", + "jazi", + "jot같", + "sex해", + "zaji", + "zazi", + "ㅅㅐㄲㅣ", + "ㅆㅣㅂㅏ", + "ㅆㅣ팍넘", + "ㅇㅍㅊㅌ", + "가슴만져", + "가슴빨아", + "가슴빨어", + "가슴핧아", + "가슴핧어", + "강간한다", + "같은새끼", + "개가튼년", + "개가튼뇬", + "개같은년", + "개거얼래", + "개거얼레", + "개념빠가", + "개보지년", + "개쓰래기", + "개쓰레기", + "개씁자지", + "개씨발넘", + "개애걸래", + "개에가튼", + "개에걸래", + "개작두넘", + "개작두년", + "개잡지랄", + "개저가튼", + "개지랄넘", + "개지랄놈", + "개후라년", + "걔잡지랄", + "거지같은", + "걸레보지", + "걸레핀년", + "게에가튼", + "게지랄놈", + "그나물에", + "나쁜새끼", + "난자마셔", + "난자먹어", + "난자핧아", + "내꺼빨아", + "내꺼핧아", + "너거애비", + "노무노무", + "누나강간", + "니씨브랄", + "니아범?", + "니할애비", + "대애가리", + "대에가리", + "더어엉신", + "더러운년", + "덜은새끼", + "돌은새끼", + "동생강간", + "뒤이치기", + "뒤져야지", + "뒤지고싶", + "뒷잇치기", + "드으응신", + "따먹는다", + "따먹었어", + "따먹었지", + "따먹을까", + "따알따리", + "떠어라이", + "또오라이", + "띠부우울", + "띠이바알", + "띠이버얼", + "띠이이발", + "띠이이벌", + "맛없는년", + "맛이간년", + "미시친발", + "미친구녕", + "미친구멍", + "미친새끼", + "미친쉐이", + "버어어지", + "버어지이", + "버지구녕", + "버지구멍", + "버지냄새", + "버지뚫어", + "버지뜨더", + "버지벌려", + "버지벌료", + "버지빨아", + "버지빨어", + "버지썰어", + "버지쑤셔", + "버지핧아", + "병신세리", + "병신셰리", + "병신씨발", + "보지구녕", + "보지구멍", + "보지뚫어", + "보지뜨더", + "보지박어", + "보지벌려", + "보지벌료", + "보지벌리", + "보지보지", + "보지빨아", + "보지빨어", + "보지자지", + "보지정액", + "보지찌져", + "보지찢어", + "보지털어", + "보지핧아", + "보지핧어", + "뷰우웅신", + "뷰웅시인", + "빙신쉐이", + "빠가야로", + "빠가십새", + "빠가씹새", + "빠아구리", + "빠아아라", + "사까시이", + "사까아시", + "새77ㅣ", + "성교하자", + "섹스하자", + "쉬이이이", + "시미발친", + "시미친발", + "시바라지", + "시바시바", + "시박색히", + "시박쉑히", + "좋은말새끼", + "시방색희", + "시방쉑희", + "시새발끼", + "시입세에", + "시친발미", + "시팍새끼", + "시팔새끼", + "십탱구리", + "십탱굴이", + "십팔새끼", + "싸가지없", + "쌍쌍보지", + "쓰래기같", + "쓰레기새", + "쓰바새끼", + "씨가랭넘", + "씨가랭년", + "씨가랭놈", + "씨박색희", + "씨박색히", + "씨박쉑히", + "씨발병신", + "씨뱅가리", + "씨벌쉐이", + "씨븡새끼", + "씨새발끼", + "씨입새에", + "씨입세에", + "씨팍새끼", + "씨팍세끼", + "씨퐁보지", + "씨퐁자지", + "씹탱굴이", + "아아가리", + "아오좋은말", + "아오시바", + "애미보지", + "애미씨뱅", + "애미자지", + "애미잡년", + "애미좃물", + "어미강간", + "엿먹어라", + "오르가즘", + "왕털버지", + "왕털보지", + "왕털자지", + "왕털잠지", + "유두빨어", + "유두핧어", + "유방만져", + "유방빨아", + "유방핧아", + "유방핧어", + "유우까압", + "자기핧아", + "자지구녕", + "자지구멍", + "자지꽂아", + "자지넣자", + "자지뜨더", + "자지뜯어", + "자지박어", + "자지빨아", + "자지빨어", + "자지쑤셔", + "자지정개", + "자지짤라", + "자지핧아", + "자지핧어", + "작은보지", + "잠지뚫어", + "젓대가리", + "젓물냄새", + "정액마셔", + "정액먹어", + "정액발사", + "정액핧아", + "정자마셔", + "정자먹어", + "정자핧아", + "조개보지", + "조개속물", + "조오가튼", + "조오까튼", + "조오오조", + "조오온니", + "조오올라", + "조온마니", + "조옴마니", + "조우까튼", + "좀쓰레기", + "좁빠라라", + "좃가튼뇬", + "좃대가리", + "좃마무리", + "좃만한것", + "좃물냄새", + "좃빠구리", + "좃빠라라", + "좋은말같은놈", + "좋은말만한년", + "좋은말만한놈", + "좋만한것", + "주둥아리", + "지이라알", + "쪼다새끼", + "창녀버지", + "창년벼지", + "캐럿닷컴", + "항문수셔", + "항문쑤셔", + "허버리년", + "허벌보지", + "허벌자식", + "허벌자지", + "헐렁보지", + "호로새끼", + "호로자슥", + "호로자식", + "호루자슥", + "후라덜넘", + "후우자앙", + "후장꽂아", + "후장뚫어", + "18년", + "18놈", + "d쥐고", + "d지고", + "me췬", + "me친", + "me틴", + "mi친", + "mi틴", + "ya동", + "ㅁㅣ췬", + "ㅂㅁㄱ", + "ㅅ.ㅂ", + "ㅅㄲ네", + "ㅅㄲ들", + "ㅅㅡ루", + "ㅆㄹㄱ", + "ㅆㅣ8", + "ㅆㅣ댕", + "ㅆㅣ뎅", + "ㅆㅣ바", + "ㅆㅣ발", + "ㅇㅒ쁜", + "좋은말.ㄴ", + "좋은말ㅏ위", + "ㅉ질한", + "ㄱㅅㄲ", + "개.웃", + "개가튼", + "개같이", + "개걸래", + "개걸레", + "개고치", + "개너미", + "개라슥", + "개마이", + "개보지", + "개부달", + "개부랄", + "개불랄", + "개붕알", + "개새기", + "개새끼", + "개색뀌", + "개색휘", + "개샛기", + "개소리", + "개쉐뀌", + "개씁년", + "개씁블", + "개씨발", + "개씨블", + "개아기", + "개자식", + "개자지", + "개잡년", + "개저씨", + "개저엇", + "개지랄", + "개후라", + "걔잡년", + "거시기", + "걸래년", + "걸레년", + "게가튼", + "게부럴", + "게저엇", + "계새끼", + "괘새끼", + "괴가튼", + "굿보지", + "김대중", + "김치녀", + "깨쌔끼", + "나빼썅", + "내미랄", + "내미럴", + "내버지", + "내씨발", + "내자지", + "내잠지", + "내조지", + "노네들", + "노알라", + "노무현", + "느그매", + "니기미", + "니미기", + "니미랄", + "니미럴", + "니아범", + "니애미", + "니애비", + "닝기리", + "닥쳐라", + "닥치세", + "달달이", + "달딸이", + "닳은년", + "대가리", + "대음순", + "더엉신", + "돈새끼", + "돌았네", + "돌으년", + "뒤져라", + "뒤져버", + "뒤져야", + "뒤져요", + "뒤지겠", + "뒤지길", + "뒤진다", + "뒤치기", + "뒷치기", + "드응신", + "디져라", + "디지고", + "따먹기", + "따먹어", + "따먹자", + "딸달이", + "딸딸이", + "떠라이", + "또라이", + "또라인", + "똘아이", + "띠발뇬", + "띠부울", + "띠브울", + "띠블넘", + "띠이발", + "띠이벌", + "막간년", + "맛간년", + "미쳣네", + "미쳤나", + "미쳤니", + "미치인", + "미친ㅋ", + "미친개", + "미친넘", + "미친년", + "미친놈", + "미친눔", + "미친새", + "미친색", + "미티넘", + "미틴것", + "방점뱅", + "백보지", + "버어지", + "버지털", + "버짓물", + "보지녀", + "보지물", + "보지털", + "보짓물", + "뷰웅신", + "빠가냐", + "빠간가", + "빠가새", + "빠가니", + "빠구리", + "빠구울", + "빠굴이", + "빠아가", + "빡새끼", + "빨치산", + "사까쉬", + "사까시", + "사새끼", + "새ㄲㅣ", + "새끼라", + "새끼야", + "성교해", + "성폭행", + "세엑스", + "세엑쓰", + "섹스해", + "소음순", + "쉬방새", + "쉬이바", + "쉬이이", + "쉽알넘", + "슈ㅣ발", + "슈우벌", + "슨상님", + "시댕이", + "시바류", + "시바알", + "시바앙", + "시발년", + "시발놈", + "시방새", + "시벌탱", + "시볼탱", + "시부럴", + "시부렬", + "시부울", + "시뷰럴", + "시뷰렬", + "시이발", + "시입세", + "시키가", + "시팔넘", + "시팔년", + "시팔놈", + "십버지", + "십부랄", + "십부럴", + "십세리", + "십세이", + "십셰리", + "십쉐끼", + "십자석", + "십자슥", + "십지랄", + "십창녀", + "십팔넘", + "싸가지", + "싸물어", + "쌍보지", + "쌔엑스", + "쎄엑스", + "씨ㅂㅏ", + "씨댕이", + "씨바라", + "씨바알", + "씨발년", + "씨발롬", + "씨방새", + "씨방세", + "씨버럼", + "씨벌년", + "씨벌탱", + "씨볼탱", + "씨부랄", + "씨부럴", + "씨부렬", + "씨불알", + "씨뷰럴", + "씨뷰렬", + "씨브럴", + "씨블년", + "씨빠빠", + "씨섹끼", + "씨이발", + "씨입새", + "씨입세", + "씨파넘", + "씨팍넘", + "씨퐁넘", + "씨퐁뇬", + "씹미랄", + "씹버지", + "씹보지", + "씹부랄", + "씹브랄", + "씹빵구", + "씹뻐럴", + "씹뽀지", + "씹새끼", + "씹쉐뀌", + "씹쌔끼", + "씹자석", + "씹자슥", + "씹자지", + "씹지랄", + "씹창녀", + "씹탱이", + "씹팔넘", + "아가리", + "애미랄", + "애애무", + "애에무", + "애에미", + "애에비", + "에애무", + "에에무", + "에에미", + "에에비", + "여어엄", + "여엄병", + "염병할", + "엿이나", + "왕버지", + "왕자지", + "왕잠지", + "왜저럼", + "유우깝", + "유우방", + "은새끼", + "이새끼", + "자압것", + "자지털", + "잠지털", + "젓같내", + "젓냄새", + "젓만이", + "정액짜", + "젖탱이", + "졌같은", + "조가튼", + "조오또", + "조오웃", + "조오지", + "조온나", + "조온니", + "조온만", + "조올라", + "조옷만", + "족같내", + "족까내", + "존.나", + "존ㄴ나", + "존나아", + "존마니", + "좀마니", + "좃간년", + "좃까리", + "좃깟네", + "좃냄새", + "좃만아", + "좃만이", + "좃보지", + "좃부랄", + "좃빠네", + "좆까라", + "좆만아", + "좆먹어", + "좆빨아", + "좆새끼", + "좋오웃", + "죠온나", + "주글년", + "주길년", + "주둥이", + "줬같은", + "지껄이", + "ㅈ1랄", + "지이랄", + "쪽바리", + "찝째끼", + "쳐받는", + "쳐발라", + "친구년", + "친노마", + "큰보지", + "페니스", + "허벌년", + "허벌레", + "허어벌", + "호냥년", + "호로자", + "호로잡", + "화낭년", + "화냥년", + "후.려", + "후라덜", + "후우장", + "미칭럼", + "느금마", + "ㅈ같네", + "ㅁㅊ", + "ㅁ친", + "ㅂㄹ", + "ㅂㅊ", + "ㅂ크", + "좋은말", + "ㅅㅍ", + "ㅅㅋ", + "ㅅ루", + "ㅅ발", + "ㅆㄺ", + "ㅆㅂ", + "ㅆㅣ", + "ㅈㄴ", + "ㅈㄹ", + "ㅈ리", + "강간", + "개간", + "개같", + "개넷", + "개년", + "개놈", + "개독", + "개련", + "개섹", + "개셈", + "개젓", + "개좆", + "개쩌", + "게젓", + "골빈", + "공알", + "구씹", + "귀두", + "꼭지", + "년놈", + "뇌텅", + "뇨온", + "늬믜", + "늬미", + "니년", + "니믜", + "니미", + "닥쳐", + "대갈", + "돈년", + "뒈져", + "뒤졌", + "뒤질", + "등신", + "디졌", + "디질", + "딴년", + "띠바", + "띠발", + "띠벌", + "띠벨", + "띠불", + "띠블", + "런년", + "럼들", + "롬들", + "맘충", + "머갈", + "믜칀", + "믜친", + "미띤", + "미췬", + "미칀", + "미친", + "미틴", + "및힌", + "발놈", + "벌창", + "벵신", + "별창", + "병닥", + "병딱", + "병맛", + "병신", + "병크", + "보지", + "봉알", + "부랄", + "불알", + "붕신", + "붕알", + "븅신", + "브랄", + "빙띤", + "빙신", + "빠굴", + "빠네", + "빠라", + "빠큐", + "빻았", + "빻은", + "뻐규", + "뻐큐", + "뻑유", + "뻑큐", + "뻨큐", + "뼈큐", + "뽀지", + "상년", + "새끼", + "새퀴", + "새킈", + "새키", + "색희", + "색히", + "샊기", + "샊히", + "샹년", + "섀키", + "성괴", + "성교", + "세끼", + "세키", + "섹끼", + "섹스", + "쇅끼", + "쇡끼", + "쉐끼", + "쉬박", + "쉬발", + "쉬버", + "쉬빡", + "쉬탱", + "쉬팍", + "쉬펄", + "쉽세", + "슈발", + "슈벌", + "스벌", + "싑창", + "시바", + "시파", + "좋은말", + "시벌", + "시빡", + "시빨", + "시탱", + "시팍", + "시팔", + "시펄", + "십녀", + "십새", + "십세", + "십창", + "십탱", + "십팔", + "싹스", + "쌍년", + "쌍놈", + "쌔끼", + "쌕스", + "쌕쓰", + "썅놈", + "썅년", + "썌끼", + "쎄끼", + "쎄리", + "쎅스", + "쎅쓰", + "쒸8", + "쒸댕", + "쒸발", + "쒸팔", + "쒸펄", + "쓰댕", + "쓰뎅", + "쓰렉", + "쓰루", + "쓰바", + "쓰발", + "쓰벌", + "쓰벨", + "쓰파", + "씌8", + "씌댕", + "씌뎅", + "씌발", + "씌벨", + "씌팔", + "씝창", + "씨8", + "씨걸", + "씨댕", + "씨뎅", + "씨바", + "씨발", + "씨벌", + "씨벨", + "씨블", + "씨븡", + "씨비", + "씨빡", + "씨빨", + "씨뻘", + "씨입", + "씨팍", + "씨팔", + "씨퐁", + "씹귀", + "씹년", + "씹덕", + "씹못", + "씹물", + "씹새", + "씹세", + "씹쌔", + "씹창", + "씹치", + "씹탱", + "씹팔", + "씹할", + "아닥", + "애무", + "애미", + "애비", + "앰창", + "야동", + "엄창", + "에무", + "에미", + "에비", + "엠생", + "엠창", + "염병", + "염뵹", + "엿같", + "옘병", + "외퀴", + "요년", + "유깝", + "유두", + "유방", + "육갑", + "은년", + "음경", + "이년", + "자위", + "자지", + "잠지", + "짬지", + "잡것", + "잡년", + "잡놈", + "저년", + "저엇", + "저엊", + "적까", + "절라", + "점물", + "젓까", + "젓떠", + "젓물", + "젓밥", + "젖같", + "젖까", + "젗같", + "젼나", + "젼낰", + "졏같", + "조깟", + "조또", + "조온", + "족까", + "존귀", + "존귘", + "존나", + "존낙", + "존내", + "존니", + "존똑", + "존맛", + "존멋", + "존버", + "존싫", + "존쎄", + "존쎼", + "존예", + "존웃", + "존잘", + "존잼", + "존좋", + "존트", + "졸귀", + "졸귘", + "졸라", + "졸맛", + "졸멋", + "졸싫", + "졸예", + "졸웃", + "졸잼", + "졸좋", + "좀물", + "좁밥", + "좃까", + "좃넘", + "좃도", + "좃또", + "좃물", + "좃털", + "종나", + "좆까", + "좆나", + "좆년", + "좆도", + "좆물", + "좆밥", + "좆털", + "좋만", + "죠낸", + "죤나", + "죤내", + "죵나", + "쥐랄", + "쥰나", + "쥰내", + "쥰니", + "쥰트", + "즤랄", + "지랄", + "지럴", + "지롤", + "지뢀", + "지뢰", + "짱깨", + "짱께", + "쪼녜", + "쪼다", + "쪽발", + "쫓같", + "쬰잘", + "창남", + "창녀", + "창년", + "창놈", + "처먹", + "첫빠", + "쳐마", + "쳐먹", + "취ㅈ", + "취좃", + "친년", + "친놈", + "파친", + "펑글", + "항문", + "허벌", + "호로", + "후려", + "후장", + "꽃휴", + "ㅂㅅ", + "걔섀", + "느금", + "늑음", + "ㅈ같", + "ㅄ", + "凸", + "뇬", + "썅", + "씹", + "좃", + "좋은말", + "좇", + "죶", + "쫂", + "쬲", + "바보", + "멍청이" +] \ No newline at end of file diff --git a/boomerang/src/main/resources/log4j2.xml b/boomerang/src/main/resources/log4j2.xml index f298c74b..158551bc 100644 --- a/boomerang/src/main/resources/log4j2.xml +++ b/boomerang/src/main/resources/log4j2.xml @@ -1,36 +1,36 @@ - - ./logs - [%-5level] %d{yyyy-MM-dd HH:mm:ss} [%t] %c{1} - %msg%n - application - - - - - - - - - - - - - - - - - - - - - - - - - + + ./logs + [%-5level] %d{yyyy-MM-dd HH:mm:ss} [%t] %c{1} - %msg%n + application + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/boomerang/src/main/resources/static/esset/footer.svg b/boomerang/src/main/resources/static/esset/footer.svg index ab3226ba..ecc4dc45 100644 --- a/boomerang/src/main/resources/static/esset/footer.svg +++ b/boomerang/src/main/resources/static/esset/footer.svg @@ -1,13 +1,24 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/boomerang/src/main/resources/static/esset/logo.svg b/boomerang/src/main/resources/static/esset/logo.svg index 62ba9231..742d6aa5 100644 --- a/boomerang/src/main/resources/static/esset/logo.svg +++ b/boomerang/src/main/resources/static/esset/logo.svg @@ -1,4 +1,8 @@ - - + + diff --git a/boomerang/src/main/resources/templates/chat_room.html b/boomerang/src/main/resources/templates/chat_room.html index c25560d7..fc3417d4 100644 --- a/boomerang/src/main/resources/templates/chat_room.html +++ b/boomerang/src/main/resources/templates/chat_room.html @@ -1,22 +1,23 @@ - - Chat Room - - + + Chat Room + +
-

Chat Room

-
- -
-
- - -
+

Chat Room

+
+ +
+
+ + +
- + + Chat Rooms + + +
-

Chat Rooms

-
- - -
-

Available Chat Rooms

-
    - -
+

Chat Rooms

+
+ + +
+

Available Chat Rooms

+
    + +