관심쟁이 영호

[ADYB] 게시판 댓글기능 구현 본문

Project/ADYB - 쇼핑몰

[ADYB] 게시판 댓글기능 구현

관심쟁이 영호 2021. 8. 5. 19:50
반응형

오늘은 게시판에 댓글기능을 구현할 예정이다.

 

목차는 다음과 같다.

 

목차

  • 도메인 설계 and 연관관계 매핑
  • Controller 구현
  • Repository 생성
  • 뷰 구현

 


도메인

 

도메인 내용은 다음과 같다.

Reply

속성 기타 설명
Long sequenceId 시퀀스 전략, Primary Key -
User user ManyToOne 관계(user가 1) 댓글 작성자
Board board ManyToOne 관계(board가 1) 댓글이 포함되는 게시글
Timestamp createDate Timestamp 작성일
String Content - 댓글 내용
@Data
@Entity(name = "reply")
public class Reply {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int replyId;

    @NotNull
    @NotBlank
    @Size(min = 1, max = 255)
    @Column(nullable = false, length = 120)
    String content;

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

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

    @CreationTimestamp
    private Timestamp createDate;



};

 

Board

Board에 Reply 추가

 

@OneToMany(mappedBy = "board")
private List<Reply> reply;

 

User

User에 Reply 추가

@OneToMany(mappedBy = "user")
private List<Reply> replyList;

 


컨트롤러 구현

 

우선 전략은 다음과 같다.

  1. board view에 댓글을 form으로 생성한다.
  2. controller와 post매핑하여 조작되도록 한다.

 

코드로 살펴보자.

@Controller
@RequiredArgsConstructor
public class ReplyController {

    @Autowired
    private final ReplyService replyService;

    @PostMapping("/reply_write")
    public String replyWrite(@ModelAttribute Reply reply, Long boardId, @SessionAttribute(name = SessionConst.LOGIN_USER, required = false)
            User user){

        return replyService.replyWrite(reply, user, boardId);

    }

    @PostMapping("/reply_delete")
    public String replyDelete(@ModelAttribute Reply reply, @SessionAttribute(name = SessionConst.LOGIN_USER, required = false)
            User user){


        return replyService.replyDelete(reply);
    }

};

 

 위 코드를 보면, 작성 및 삭제를 post로 나누어 놓았다.

 

이제 Repository를 만들고 컨트롤러에 적용해보자.

 


Repository 생성

 

Repository는 Spring JPA data를 이용한다.

 

ReplyRepository

public interface ReplyRepository extends JpaRepository<Reply, Long> {
};

 

 


Service 생성

 

ReplyService

 

@Service
@RequiredArgsConstructor
public class ReplyService {

    @Autowired
    private final ReplyRepository replyRepository;

    @Autowired
    private final BoardRepository boardRepository;

    @Autowired
    private final UserRepository userRepository;

    public String replyWrite(Reply reply, User user, Long boardId){

        User findUser = userRepository.findByUserId(user.getUserId());
        Optional<Board> findBoard = boardRepository.findById(boardId);

        reply.setBoard(findBoard.get());
        reply.setUser(findUser);
        replyRepository.save(reply);

        return "home";
    }

    public String replyDelete(Reply reply){

        replyRepository.delete(reply);

        return "home";
    }

};

 

Write 부분에서는 board, user을 설정해주고 저장했다.

 

Delete 부분에서는 해당 reply만 삭제해주었다.

(User, board는 어차피 mappedBy 처리라서 따로 처리해주지 않아도 된다.)

 


뷰 구현

 

기존에 있던 페이지에서 추가해보자!

 

기존페이지는 다음과 같다.

(Thymeleaf를 사용했다.)

 

<!DOCTYPE html>
<html th:replace="~{layouts/base :: layout(~{::title},~{::section})}"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <title>게시판 조회</title>
</head>
<body>
<section class="masthead text-center">

    <div class="jumbotron"  th:object="${board}">
        <h1 class="display-4" th:text="${board.title}">Hello, world!</h1>
        <br>
        <hr>
        <br>
        <div th:each="path : ${board.userFileList}">
            <br>
            <img th:src="${path.filePath}" class="card-img-top" alt="..." style="width: 200px; height 300px;">
            <br>
        </div>
        <br><hr><br>
        <p class="lead" th:text="${board.content}">This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.</p>
        <hr><br>
        <p th:text="${board.user.userId}">It uses utility classes for typography and spacing to space content out within the larger container.</p>

        <br><hr><br>

        <!-- Reply Section -->

        <div class="input-group mb-3">

            <form id="reply" action="/reply_write" method="post">
                <input type="text" id="content" name="content" class="form-control" placeholder="댓글을 입력해주세요.." aria-label="댓글을 입력해주세요.." aria-describedby="basic-addon2">
                <input type="hidden" id="boardId" name="boardId" th:value="${board.boardId}">
                <div class="input-group-append">
                    <button class="btn btn-outline-secondary" type="submit">등록</button>
                </div>
            </form>
        </div>



        <!-- Reply Section End -->
        <p class="lead">
            <a class="btn btn-primary btn-lg" href="/board" role="button">목록으로</a>
        </p>
    </div>

</section>
</body>
</html>

Reply 기능은 form으로 이루어져 있다.

Reply 기능의 내용은 content이고, hidden으로 정의되어있는 것은 해당 board의 id를 넘기는 것이다. (매핑에 필요하기 때문에)

 


기타 입터셉터 처리까지 해주었다!

 

끝!

 

 

300x250
Comments