Spring 심화 프로젝트 Start

신성훈·2024년 7월 11일

TIL

목록 보기
58/162
post-thumbnail

이번 프로젝트에서 담당 -> Board

  • Board
    -Entity
package com.sparta.refrigerator.board.entity;

import com.sparta.refrigerator.board.dto.BoardRequestDTO;
import com.sparta.refrigerator.common.TimeStamp;
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.OneToMany;
import jakarta.persistence.Table;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.security.core.userdetails.User;

@Entity
@Getter
@NoArgsConstructor
@Table(name = "boards")
public class Board extends TimeStamp {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String boardName;

    @Column(nullable = false)
    private String boardInfo;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    @OneToMany(mappedBy = "board")
    private List<Invitation> invitations = new ArrayList<>();

    public Board(BoardRequestDTO requestDTO) {
        this.boardName = requestDTO.getBoardName();
        this.boardInfo = requestDTO.getBoardInfo();
        this.user = user;
    }

    public void update(BoardRequestDTO requestDTO) {
        this.boardName = requestDTO.getBoardName();
        this.boardInfo = requestDTO.getBoardInfo();
    }

}

-Contoroller

package com.sparta.refrigerator.board.controller;

import com.sparta.refrigerator.board.dto.BoardRequestDTO;
import com.sparta.refrigerator.board.dto.BoardResponseDTO;
import com.sparta.refrigerator.board.dto.InvitationRequestDTO;
import com.sparta.refrigerator.board.service.BoardService;
import com.sparta.refrigerator.common.response.DataCommonResponse;
import com.sparta.refrigerator.common.response.StatusCommonResponse;
import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
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.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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class BoardController {

    private final BoardService boardService;

    //Board 생성
    @PostMapping("/admin/board")
    public ResponseEntity<DataCommonResponse<BoardResponseDTO>> createBoard(
        @RequestBody @Valid BoardRequestDTO requestDTO,
        @AuthenticationPrincipal UserDetailsImpl userDetails) {
        BoardResponseDTO board = boardService.createBoard(requestDTO, userDetails.getUser());
        DataCommonResponse<BoardResponseDTO> response = new DataCommonResponse<>(201, "보드 작성되었습니다.",
            board);
        return new ResponseEntity<>(response, HttpStatus.CREATED);
    }

    //Board 수정
    @PutMapping("/admin/boards/{boardId}")
    public ResponseEntity<DataCommonResponse<BoardResponseDTO>> updateBoard(
        @PathVariable(value = "boardId") Long boardId,
        @RequestBody @Valid BoardRequestDTO requestDTO,
        @AuthenticationPrincipal UserDetailsImpl userDetails) {
        BoardResponseDTO board = boardService.updateBoard(boardId, requestDTO,
            userDetails.getUser());
        DataCommonResponse<BoardResponseDTO> response = new DataCommonResponse<>(200,
            "보드 수정이 완료 되었습니다.", board);
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

    //Board 삭제
    @DeleteMapping("/admin/boards/{boardId}")
    public ResponseEntity<StatusCommonResponse> deleteBoard(
        @PathVariable(value = "boardId") Long boardId,
        @AuthenticationPrincipal UserDetailsImpl userDetails) {
        boardService.deleteBoard(boardId, userDetails.getUser());
        StatusCommonResponse response = new StatusCommonResponse(204, "보드 삭제되었습니다.");
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

    //Board 초대
    @PostMapping("/admin/boards/{boardId}/invitation")
    public ResponseEntity<DataCommonResponse<String>> inviteBoard(
        @PathVariable(value = "boardId") Long boardId,
        @AuthenticationPrincipal UserDetailsImpl userDetails,
        @RequestBody @Valid InvitationRequestDTO requestDTO) {

        boardService.inviteBoard(boardId, userDetails.getUser(), requestDTO);
        DataCommonResponse<String> response = new DataCommonResponse<>(200, "보드 초대가 완료었습니다.",
            "초대 성공");

        return new ResponseEntity<>(response, HttpStatus.OK);
    }

    //Board 단건 조회
    @GetMapping("/boards/{boardId}")
    public ResponseEntity<DataCommonResponse<BoardResponseDTO>> viewBoard(
        @PathVariable(value = "boardId") Long boardId) {
        BoardResponseDTO board = boardService.viewBoard(boardId);
        DataCommonResponse<BoardResponseDTO> response = new DataCommonResponse<>(200,
            "보드 단건 조회 성공하였습니다.", board);
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

    //Board 전체 조회
    @GetMapping("/boards")
    public ResponseEntity<DataCommonResponse<Page<BoardResponseDTO>>> viewAllBoard(
        @RequestParam(value = "page", defaultValue = "0") int page,
        @RequestParam(value = "size", defaultValue = "5") int size) {
        Page<BoardResponseDTO> responseDTOPage = boardService.viewAllBoard(page, size);
        DataCommonResponse<Page<BoardResponseDTO>> response = new DataCommonResponse<>(200,
            "보드 전체 조회 성공하였습니다.", responseDTOPage);
        return new ResponseEntity<>(response, HttpStatus.OK);

    }
}

-Service

package com.sparta.refrigerator.board.service;

import com.sparta.refrigerator.board.dto.BoardRequestDTO;
import com.sparta.refrigerator.board.dto.BoardResponseDTO;
import com.sparta.refrigerator.board.dto.InvitationRequestDTO;
import com.sparta.refrigerator.board.entity.Board;
import com.sparta.refrigerator.board.entity.Invitation;
import com.sparta.refrigerator.board.repository.BoardRepository;
import com.sparta.refrigerator.board.repository.InvitationRepository;
import com.sparta.refrigerator.exception.DataNotFoundException;
import com.sparta.refrigerator.exception.ForbiddenException;
import com.sparta.refrigerator.exception.ViolatedException;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class BoardService {

    private final BoardRepository boardRepository;
    private final UserRepository userRepository;
    private final InvitationRepository invitationRepository;

    //Board 생성
    public BoardResponseDTO createBoard(BoardRequestDTO requestDTO, User user) {
        if (user.getRole() == User.Role.MANAGER) {
            Board board = new Board(requestDTO);
            boardRepository.save(board);
            return new BoardResponseDTO(board);
        } else {
            throw new ForbiddenException("권한에 맞지 않은 사용자는 요청을 진행할 수 없습니다.");
        }
    }

    //Board 수정
    @Transactional
    public BoardResponseDTO updateBoard(Long boardId, BoardRequestDTO requestDTO, User user) {
        Board board = boardRepository.findById(boardId).orElseThrow(
            () -> new DataNotFoundException("선택한 게시물이 없습니다."));

        userRepository.findById(user.userId()).orElseThrow(
            () -> new DataNotFoundException("선택한 유저를 찾을 수 없습니다."));

        if (!board.getUser().getRole().equals(user.getRole())) {
            throw new ForbiddenException("권한에 맞지 않은 사용자는 요청을 진행할 수 없습니다.");
        }
        board.update(requestDTO);
        boardRepository.save(board);
        return new BoardResponseDTO(board);
    }

    //Board 삭제
    public void deleteBoard(Long boardId, User user) {
        Board board = boardRepository.findById(boardId).orElseThrow(
            () -> new DataNotFoundException("선택한 게시물이 없습니다."));

        userRepository.findById(user.userId()).orElseThrow(
            () -> new DataNotFoundException("선택한 유저를 찾을 수 없습니다."));

        if (!board.getUser().getRole().equals(user.getRole())) {
            throw new ForbiddenException("권한에 맞지 않은 사용자는 요청을 진행할 수 없습니다.");
        }
        boardRepository.delete(board);
    }

    //Board 초대
    @Transactional
    public void inviteBoard(Long boardId, User user , InvitationRequestDTO requestDTO) {
        Board board = boardRepository.findById(boardId).orElseThrow(
            () -> new DataNotFoundException("선택한 게시물이 없습니다."));

        if (!user.getRole().equals(User.Role.MANAGER)) {
            throw new ForbiddenException("권한에 맞지 않은 사용자는 요청을 진행할 수 없습니다.");
        }

        User invitee = userRepository.findByUsername(requestDTO.getUserName()).orElseThrow(
            () -> new DataNotFoundException("초대할 사용자가 없습니다."));

        boolean isAlreadyInvited = invitationRepository.existsByBoardAndUser(board, invitee);
        if (isAlreadyInvited) {
            throw new ViolatedException("이미 해당 보드에 초대된 사용자입니다.");
        }

        Invitation invitation = new Invitation(board, invitee);
        invitationRepository.save(invitation);
    }

    //Board 단건 조회
    public BoardResponseDTO viewBoard(Long boardId) {
        return boardRepository.findById(boardId)
            .map(BoardResponseDTO::new)
            .orElseThrow(() -> new DataNotFoundException("선택한 게시물이 없습니다."));

    }

    //Board 전체 조회
    public Page<BoardResponseDTO> viewAllBoard(int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        Page<Board> boardPage = boardRepository.findAllByOrderByCreatedAtDesc(pageable);

        if (boardPage.isEmpty()) {
            throw new DataNotFoundException("먼저 작성하여 소식을 알려보세요!");
        }

        return boardPage.map(BoardResponseDTO::new);
    }
}

-Repository

package com.sparta.refrigerator.board.repository;

import com.sparta.refrigerator.board.entity.Board;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BoardRepository extends JpaRepository <Board, Long> {

    Page<Board> findAllByOrderByCreatedAtDesc(Pageable pageable);
}

-BoardRequestDTO

package com.sparta.refrigerator.board.dto;

import jakarta.validation.constraints.NotBlank;
import lombok.Getter;

@Getter
public class BoardRequestDTO {

    @NotBlank(message = "추가할 보드의 이름을 입력해주세요.")
    private String boardName;
    @NotBlank(message = "추가할 보드의 내용을 입력해주세요.")
    private String boardInfo;

}

-BoardResponseDTO

package com.sparta.refrigerator.board.dto;

import com.sparta.refrigerator.board.entity.Board;
import lombok.Getter;

@Getter
public class BoardResponseDTO {
    private Long id;
    private String boardName;
    private String boardInfo;
    private Long userId;

    public BoardResponseDTO(Board board) {
        this.id = board.getId();
        this.boardName = board.getBoardName();
        this.boardInfo = board.getBoardInfo();
        this.userId = board.getUser().getId();
    }
}
  • Invitation
    -Entity
package com.sparta.refrigerator.board.entity;

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 lombok.Getter;
import org.springframework.security.core.userdetails.User;

@Entity
@Getter
public class Invitation {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "board_id")
    private Board board;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    public Invitation(Board board, User user) {
        this.board = board;
        this.user = user;
    }
}

-Repository

package com.sparta.refrigerator.board.repository;

import com.sparta.refrigerator.board.entity.Board;
import com.sparta.refrigerator.board.entity.Invitation;
import org.springframework.data.jpa.repository.JpaRepository;

public interface InvitationRepository extends JpaRepository <Invitation, Long> {
    boolean existsByBoardAndUser(Board board, User user);
}

-InvitationRequestDTO

package com.sparta.refrigerator.board.dto;

import jakarta.validation.constraints.NotBlank;
import lombok.Getter;

@Getter
public class InvitationRequestDTO {

    @NotBlank(message = "초대할 사용자 이름을 입력해주세요.")
    private String userName;
}
profile
조급해하지 말고, 흐름을 만들고, 기록하면서 쌓아가자.

0개의 댓글