Spring Boot

[게시판 만들기 (5)] 게시글 조회

서윤-정 2024. 1. 14. 02:23

 

 

BoardController에 findById 메서드를 추가한다.

특정 ID에 해당하는 게시글을 조회하고, 해당 게시글의 조회수를 증가시킨 후에

상세페이지(detail.html)로 이동하는 메서드이다.

 

[ BoardController ]

@GetMapping("/{id}")
public String findById(@PathVariable Long id, Model model){
    /*
        해당 게시글의 조회수를 하나 올리고
        게시글 데이터를 가져와서 detail.html에 출력
     */
    boardService.updateHits(id);
    BoardDTO boardDTO = boardService.findById(id);
    model.addAttribute("board", boardDTO);
    return "detail";
}

 

public String findById(@PathVariable Long id, Model model){

@PathVariable 어노테이션을 사용하여 URL 경로에서 추출한 'id' 값을 메서드의 매개변수로 받는다.

Model 객체는 뷰에 데이터를 전달하기 위한 스프링의 클래스이다.

 

boardService.updateHits(id);

boardService를 통해 updateHits 메서드를 호출하여 해당 id에 해당하는 게시글의 조회수를 증가시킨다.

 

BoardDTO boardDTO = boardService.findById(id);

boardService를 통해 findById 메서드를 호출하여 해당 id에 해당하는 게시글의 정보를 가져온다.

 

model.addAttribute("board", boardDTO);

Model 객체에 board라는 속성명으로 boardDTO를 추가한다.

이를 통해 해당 데이터를 뷰로 전달할 수 있다.

 

return "detail";

최종적으로 detail이라는 뷰 이름을 반환한다. 

 

 

 

 

 

 

 

 

 

 

 

BoardService 클래스에 updateHits 메서드와 findById 메서드를 추가한다.

 

[ BoardService ]

@Transactional
public void updateHits(Long id) {
    boardRepository.updateHits(id);
}

public BoardDTO findById(Long id) {
    Optional<BoardEntity> optionalBoardEntity = boardRepository.findById(id);
    if (optionalBoardEntity.isPresent()) {
        BoardEntity boardEntity = optionalBoardEntity.get();
        BoardDTO boardDTO = BoardDTO.toBoardDTO(boardEntity);
        return boardDTO;
    } else {
        return null;
    }
}

 

<updateHits 메서드>

 

@Transactional

이 어노테이션은 해당 메서드가 트랜잭션 내에서 실행되어야 함을 나타낸다

 

public void updateHits(Long id) {

해당 ID에 해당하는 게시글의 조회수를 업데이트 하는 메서드이다.

 boardRepository.updateHits(id); 를 호출하여 게시글 조회수를 업데이트한다.

이는 커스텀 쿼리를 사용하여 해당 ID에 해당하는 게시글의 조회수를 증가시키는 쿼리를 실행한다.

 

 

<findById 메서드>

 

public BoardDTO findById(Long id) {

해당 ID에 해당하는 게시글을 가져오는 메서드이다.

boardRepository.findById(id); 를 호출하여 Optional<BoardEntity> 객체를 얻는다.

이 객체는 게시글이 존재할 수도, 존재하지 않을 수도 있다.

if (optionalBoardEntity.isPresent()) { 를 사용하여 게시글이 존재하는지 확인하고,

존재한다면  BoardEntity boardEntity = optionalBoardEntity.get(); 로 BoardEntity 객체를 가져와            

BoardDTO.toBoardDTO(boardEntity); 를 통해

return boardDTO; 인 BoardDTO로 변환하여 반환한다.

게시글이 존재하지 않으면 null을 반환한다. 

 

 

 

 

 

 

 

 

 

 

 

 

BoardRepository 인터페이스에 커스텀 쿼리를 정의한다.

 

[ BoardRepository ]

public interface BoardRepository extends JpaRepository<BoardEntity, Long> {
    // update board_table set board_hits=board_hits+1 where id=?
    @Modifying
    @Query(value = "update BoardEntity b set b.boardHits=b.boardHits+1 where b.id=:id")
    void updateHits(@Param("id") Long id);
}

 

@Modifying

이 어노테이션은 JPQL(QueryDSL를 통해 작성된 쿼리)을 사용하여 데이터를 수정하는 메서드임을 나타낸다.

JPQL은 객체지향 쿼리 언어로, 엔티티 객체를 기반으로 쿼리를 작성할 수 있다.

 

@Query(value = "update BoardEntity b set b.boardHits=b.boardHits+1 where b.id=:id")

JPQL 쿼리를 정의한다. 

이 쿼리는 BoardEntity 의 조회수 (boardHits)를 1증가시키는 업데이트 쿼리이다.

:id는 쿼리에 사용되는 매개변수로, 실제 실행 시에 파라미터로 전달된다.

 

void updateHits(@Param("id") Long id);

쿼리 메서드로, 조회수를 업데이트 하는 역할을 한다.

@Param("id") 어노테이션은 메서드 파라미터와 JPQL 쿼리의 매개변수를 연결한다.

이 경우, 메서드 파라미터 id가 JPQL 쿼리의 :id 매개변수에 바인딩된다.

 

 

 

 

 

 

 

 

 

 

 

 

templates 패키지에 detail.html 파일을 추가한다.

 

[ detail.html ]

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>detail</title>
    <!-- jquery cdn -->
    <script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script>
</head>
<body>
<table>
    <tr>
        <th>id</th>
        <td th:text="${board.id}"></td>
    </tr>
    <tr>
        <th>title</th>
        <td th:text="${board.boardTitle}"></td>
    </tr>
    <tr>
        <th>writer</th>
        <td th:text="${board.boardWriter}"></td>
    </tr>
    <tr>
        <th>date</th>
        <td th:text="${board.boardCreatedTime}"></td>
    </tr>
    <tr>
        <th>hits</th>
        <td th:text="${board.boardHits}"></td>
    </tr>
    <tr>
        <th>contents</th>
        <td th:text="${board.boardContents}"></td>
    </tr>
    <tr th:if="${board.fileAttached == 1}">
        <th>image</th>
        <td><img th:src="@{|/upload/${board.storedFileName}|}" alt=""></td>
    </tr>
</table>
<button onclick="listReq()">목록</button>
<button onclick="updateReq()">수정</button>
<button onclick="deleteReq()">삭제</button>

</body>
<script th:inline="javascript">
    const listReq = () => {
        console.log("목록 요청");
        const page = [[${page}]];
        location.href = "/board/paging?page="+page;
    }
    const updateReq = () => {
        console.log("수정 요청");
        const id = [[${board.id}]];
        location.href = "/board/update/" + id;
    }
    const deleteReq = () => {
        console.log("삭제 요청");
        const id = [[${board.id}]];
        location.href = "/board/delete/" + id;
    }
</script>
</html>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

실행시켜보쟈.

http://localhost:8092/board/1 의 detail 화면이다.

조회수는 새로고침하는대로 늘어난다.