협업 도구 프로젝트 2일차
- 1일차 내용 :
개발환경
- Spring Boot 3.2.3
- Spring Security
- Spring Data JPA
- Spring Lombok
- Gradle 8.6
- JAVA 17
- MySQL 8.3
진행상황
- 저는 협업 툴 프로젝트에서 보드와 댓글 기능을 담당했습니다.
- 먼저 CRUD가 가능한 상태만 될 수 있도록 기능 구현을 하고 필요한 기능들을 조금씩 추가해 나가기로 결정했습니다.
코드
- 유저 기능이 구현되지 않은 상태이기 때문에 필요한 userId는 임의로 1을 주었습니다.
- 생성시간과 수정시간은 따로 시간을 관리할 수 있는 class로 분리하여 처리하려고 생각했습니다. (앞으로 해야할 기능구현 중 하나)
- 기능구현을 하면서 필요한 부분은 todo로 한번에 볼 수 있게 했습니다. (밑에 코드에는 지워둔 상태입니다.)
- 이제 협업 인원들을 초대하는 기능과 생성자만 수정 삭제할 수 있게 하는 기능 구현을 해보려고 합니다.
- board (협업이 이루어지는 공간)
-
더보기entity
package com.fis.mylittleboard.domain.board.entity; import com.fis.mylittleboard.domain.board.dto.BoardRequestDto; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; import java.time.LocalDateTime; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.annotation.CreatedDate; @Entity @Getter @NoArgsConstructor @Table(name = "boards") public class Board { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String boardName; @Column(nullable = false) private String boardDescription; @Column(nullable = false) private String boardColor; @Column(nullable = false) private Long userId; @CreatedDate @Column(nullable = false) private LocalDateTime dueDate = LocalDateTime.now(); @Column(nullable = false) private boolean classification; public Board(String boardName, String boardDescription, String boardColor, Long userId) { this.boardName = boardName; this.boardDescription = boardDescription; this.boardColor = boardColor; this.userId = userId; } public void update(BoardRequestDto requestDto) { this.boardName = requestDto.getBoardName(); this.boardDescription = requestDto.getBoardDescription(); this.boardColor = requestDto.getBoardColor(); this.dueDate = LocalDateTime.now(); } }
dto
package com.fis.mylittleboard.domain.board.dto; import lombok.Getter; @Getter public class BoardRequestDto { private String boardName; private String boardDescription; private String boardColor; }
package com.fis.mylittleboard.domain.board.dto; import java.time.LocalDateTime; import lombok.Getter; @Getter public class BoardResponseDto { private String boardName; private String boardDescription; private String boardColor; private LocalDateTime dueDate; public BoardResponseDto( String boardName, String boardDescription, String boardColor, LocalDateTime dueDate) { this.boardName = boardName; this.boardDescription = boardDescription; this.boardColor = boardColor; this.dueDate = dueDate; } }
controllerpackage com.fis.mylittleboard.domain.board.controller; import com.fis.mylittleboard.domain.board.dto.BoardRequestDto; import com.fis.mylittleboard.domain.board.dto.BoardResponseDto; import com.fis.mylittleboard.domain.board.serivce.BoardService; import java.util.List; import lombok.RequiredArgsConstructor; import org.apache.coyote.Response; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; 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 @RequestMapping("/api/boards") public class BoardController { private final BoardService boardService; @PostMapping public String createBoard ( @RequestBody BoardRequestDto requestDto) { boardService.createBoard(requestDto); return "작업공간이 생성되었습니다."; } @GetMapping("/progress") public ResponseEntity<List<BoardResponseDto>> getBoardProgressing() { List<BoardResponseDto> responseDtoList = boardService.getBoardProgressing(); return new ResponseEntity<>(responseDtoList, HttpStatus.OK); } @GetMapping("/close") public ResponseEntity<List<BoardResponseDto>> getBoardClosing() { List<BoardResponseDto> responseDtoList = boardService.getBoardClosing(); return new ResponseEntity<>(responseDtoList, HttpStatus.OK); } @PutMapping("/{boardId}") public String updateBoard( @PathVariable Long boardId, @RequestBody BoardRequestDto requestDto) { boardService.updateBoard(boardId, requestDto); return "워크스페이스가 수정되었습니다."; } @DeleteMapping("/{boardId}") public String deleteBoard( @PathVariable Long boardId) { boardService.deleteBoard(boardId); return "워크스페이스가 삭제되었습니다."; } }
service
package com.fis.mylittleboard.domain.board.serivce; import com.fis.mylittleboard.domain.collaboration.entity.Collaboration; import com.fis.mylittleboard.domain.collaboration.repository.CollaborationRepository; import com.fis.mylittleboard.domain.board.dto.BoardRequestDto; import com.fis.mylittleboard.domain.board.dto.BoardResponseDto; import com.fis.mylittleboard.domain.board.entity.Board; import com.fis.mylittleboard.domain.board.repository.BoardRepository; import com.fis.mylittleboard.domain.hahaboard.entity.Hahaboard; import com.fis.mylittleboard.domain.hahaboard.repository.HahaboardRepository; import java.util.ArrayList; import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Slf4j @Service @RequiredArgsConstructor public class BoardService { private final BoardRepository boardRepository; private final CollaborationRepository collaborationRepository; private final HahaboardRepository hahaboardRepository; @Transactional public void createBoard(BoardRequestDto requestDto) { Long userId = 1L; String boardName = requestDto.getBoardName(); Optional<Board> checkBoardName = boardRepository.findByBoardName(boardName); if (checkBoardName.isPresent()) { throw new IllegalArgumentException("사용중인 작업공간입니다."); } Board board = new Board( requestDto.getBoardName(), requestDto.getBoardDescription(), requestDto.getBoardColor(), userId ); Board newBoard = boardRepository.save(board); Hahaboard hahaboard = new Hahaboard(newBoard.getId()); hahaboardRepository.save(hahaboard); Collaboration collaboration = new Collaboration(newBoard.getId(), userId); collaborationRepository.save(collaboration); } @Transactional(readOnly = true) public List<BoardResponseDto> getBoardProgressing() { List<BoardResponseDto> boardResponseDtoList = new ArrayList<>(); for (Board board : boardRepository.findAll()) { if (board.isClassification()) { boardResponseDtoList.add( new BoardResponseDto( board.getBoardName(), board.getBoardDescription(), board.getBoardColor(), board.getDueDate())); } } return boardResponseDtoList; } @Transactional(readOnly = true) public List<BoardResponseDto> getBoardClosing() { List<BoardResponseDto> boardResponseDtoList = new ArrayList<>(); for(Board board : boardRepository.findAll()) { if (!board.isClassification()) { boardResponseDtoList.add( new BoardResponseDto( board.getBoardName(), board.getBoardDescription(), board.getBoardColor(), board.getDueDate())); } } return boardResponseDtoList; } @Transactional public void updateBoard(Long boardId, BoardRequestDto requestDto) { Board board = boardRepository.findById(boardId).orElseThrow(() -> new IllegalArgumentException("일치하는 작업공간이 없습니다.")); board.update(requestDto); } @Transactional public void deleteBoard(Long boardId) { boardRepository.deleteById(boardId); } }
repository
package com.fis.mylittleboard.domain.board.repository; import com.fis.mylittleboard.domain.board.entity.Board; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface BoardRepository extends JpaRepository<Board, Long> { Optional<Board> findByBoardName(String boardName); }
-
- collaboration (사용자와 보드의 중간 테이블)
-
더보기entity
package com.fis.mylittleboard.domain.board.repository; import com.fis.mylittleboard.domain.board.entity.Board; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface BoardRepository extends JpaRepository<Board, Long> { Optional<Board> findByBoardName(String boardName); }
package com.fis.mylittleboard.domain.board.repository; import com.fis.mylittleboard.domain.board.entity.Board; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface BoardRepository extends JpaRepository<Board, Long> { Optional<Board> findByBoardName(String boardName); }
-
- hahacontent (소소한 일들을 공유할 수 있는 공간)
-
더보기entity
package com.fis.mylittleboard.domain.hahacontent.entity; import com.fis.mylittleboard.domain.hahacontent.dto.HahaContentRequestDto; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; import java.time.LocalDateTime; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; @Entity @NoArgsConstructor @Getter @Table(name = "hahacontents") public class HahaContent { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String content; @Column private Long hahaboardId; @CreatedDate private LocalDateTime createdAt; @LastModifiedDate private LocalDateTime modifiedAt; public HahaContent(Long hahaboardId, HahaContentRequestDto requestDto) { this.content = requestDto.getContent(); this.hahaboardId = hahaboardId; this.createdAt = LocalDateTime.now(); this.modifiedAt = LocalDateTime.now(); } }
dto
package com.fis.mylittleboard.domain.hahacontent.dto; import lombok.Getter; @Getter public class HahaContentRequestDto { private String content; }
package com.fis.mylittleboard.domain.hahacontent.dto; import lombok.Getter; @Getter public class HahaContentResponseDto { private String content; }
controller
package com.fis.mylittleboard.domain.hahacontent.controller; import com.fis.mylittleboard.domain.hahacontent.dto.HahaContentRequestDto; import com.fis.mylittleboard.domain.hahacontent.service.HahaContentService; import lombok.RequiredArgsConstructor; 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 @RequiredArgsConstructor @RequestMapping("/api") public class HahaContentController { private final HahaContentService hahaContentService; @PostMapping("/hahaboards/{hahaboardId}") public String createHahaContent ( @PathVariable Long hahaboardId, @RequestBody HahaContentRequestDto requestDto) { hahaContentService.createHahaContent(hahaboardId, requestDto); return "잡담글이 생성되었읍니다."; } }
service
package com.fis.mylittleboard.domain.hahacontent.service; import com.fis.mylittleboard.domain.hahacontent.dto.HahaContentRequestDto; import com.fis.mylittleboard.domain.hahacontent.entity.HahaContent; import com.fis.mylittleboard.domain.hahacontent.repository.HahaContentRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor public class HahaContentService { private final HahaContentRepository hahaContentRepository; public void createHahaContent(Long hahaboardId, HahaContentRequestDto requestDto) { HahaContent content = new HahaContent(hahaboardId, requestDto); hahaContentRepository.save(content); } }
repository
package com.fis.mylittleboard.domain.hahacontent.repository; import com.fis.mylittleboard.domain.hahacontent.entity.HahaContent; import org.springframework.data.jpa.repository.JpaRepository; public interface HahaContentRepository extends JpaRepository<HahaContent, Long> { }
-
- hahaboard
-
더보기entity
package com.fis.mylittleboard.domain.hahaboard.entity; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.IdClass; import jakarta.persistence.Table; import java.awt.dnd.InvalidDnDOperationException; import java.time.LocalDateTime; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.annotation.CreatedDate; @Entity @NoArgsConstructor @Getter @Table(name = "hahaboard") public class Hahaboard { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private Long InBoardId; @CreatedDate private LocalDateTime createdAt; public Hahaboard(Long id) { this.InBoardId = id; this.createdAt = LocalDateTime.now(); } }
repository
package com.fis.mylittleboard.domain.hahaboard.repository; import com.fis.mylittleboard.domain.hahaboard.entity.Hahaboard; import org.springframework.data.jpa.repository.JpaRepository; public interface HahaboardRepository extends JpaRepository<Hahaboard, Long> { }
-
- comment (댓글)
-
더보기entity
package com.fis.mylittleboard.domain.comment.entity; import com.fis.mylittleboard.domain.comment.dto.CommentRequestDto; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; @Entity @Getter @NoArgsConstructor @Table(name = "comments") public class Comment { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String content; public Comment(CommentRequestDto requestDto) { this.content = requestDto.getContent(); } public void update(CommentRequestDto requestDto) { this.content = requestDto.getContent(); } }
dto
package com.fis.mylittleboard.domain.comment.dto; import lombok.Getter; @Getter public class CommentRequestDto { private String content; }
package com.fis.mylittleboard.domain.comment.dto; import lombok.Getter; @Getter public class CommentResponseDto { private String content; }
controller
package com.fis.mylittleboard.domain.comment.controller; import com.fis.mylittleboard.domain.comment.dto.CommentRequestDto; import com.fis.mylittleboard.domain.comment.service.CommentService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.DeleteMapping; 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 @RequestMapping("/api/comments") public class CommentController { private final CommentService commentService; @PostMapping public String createComment ( @RequestBody CommentRequestDto requestDto) { commentService.createCommnet(requestDto); return "댓글이 생성되었습니다"; } @PutMapping("/{commentId}") public String updateComment ( @PathVariable Long commentId, @RequestBody CommentRequestDto requestDto) { commentService.updateComment(commentId, requestDto); return "댓글이 수정되었습니다."; } @DeleteMapping("/{commentId}") public String deleteComment ( @PathVariable Long commentId) { commentService.deleteComment(commentId); return "댓글이 삭제되었습니다."; } }
service
package com.fis.mylittleboard.domain.comment.service; import com.fis.mylittleboard.domain.comment.dto.CommentRequestDto; import com.fis.mylittleboard.domain.comment.entity.Comment; import com.fis.mylittleboard.domain.comment.repository.CommentRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor public class CommentService { private final CommentRepository commentRepository; public void createCommnet(CommentRequestDto requestDto) { Comment comment = new Comment(requestDto); commentRepository.save(comment); } @Transactional public void updateComment(Long commentId, CommentRequestDto requestDto) { Comment comment = commentRepository.findById(commentId).orElseThrow(() -> new IllegalArgumentException("존재하지 않는 댓글입니다.")); comment.update(requestDto); } public void deleteComment(Long commentId) { commentRepository.deleteById(commentId); } }
repository
package com.fis.mylittleboard.domain.comment.repository; import com.fis.mylittleboard.domain.comment.entity.Comment; import org.springframework.data.jpa.repository.JpaRepository; public interface CommentRepository extends JpaRepository<Comment, Long> { }
-
회고
그 동안의 프로젝트를 진행하면서 ERD와 API 설계의 중요성을 매번 느끼면서 이번에는 최대한 완벽하게 설계하겠다는 생각으로 설계를 했지만 중간에 계속되는 추가와 수정이 있었습니다.
개발을 하는 것도 중요하지만 처음 설계의 중요성을 프로젝트마다 느낄 수 있고 조금씩 성장하는 것을 느낄 수 있어 힘들지만 재밌게 프로젝트를 할 수 있는 것 같습니다.
'Project > Kanban Board' 카테고리의 다른 글
[JAVA / Spring / JPA / Project] - 협업 도구 프로젝트 1일차 (0) | 2024.03.18 |
---|