Java/JPA

JPA 기초(comment) - AWS 풀스택 과정 83일차

awspspgh 2024. 11. 22. 09:36
목차
1. paging
2. comment

 

1. paging

list.html

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
        layout:decorate="~{layout/layout}">

<div layout:fragment="content">
    <div class="container-md">
        <h1>Board List Page</h1>
        <table class="table table-hover">
            <thead>
            <tr>
                <th>#</th>
                <th>title</th>
                <th>writer</th>
                <th>regDate</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="bvo:${list}">
                <td>[[${bvo.bno}]]</td>
                <td><a th:href="@{/board/detail(bno=${bvo.bno})}">[[${bvo.title}]]</a></td>
                <td>[[${bvo.writer}]]</td>
                <td>[[${bvo.regAt}]]</td>
            </tr>
            </tbody>
        </table>

        <!-- 페이지네이션 라인 -->
        <!-- th:classappend : 동적 클래스 추가 -->

        <nav aria-label="Page navigation example">
            <ul class="pagination justify-content-center">
                <li th:if="${pgvo.hasPrev}" class="page-item">
                    <a class="page-link" th:href="@{/board/list(pageNo = ${pgvo.startPage - 1})}" aria-label="Previous">
                        <span aria-hidden="true">&laquo;</span>
                    </a>
                </li>

                <th:block th:each="i : ${#numbers.sequence(pgvo.startPage, pgvo.endPage)}">
                    <li class="page-item" aria-current="page" th:classappend="${pgvo.pageNo eq i ? 'active' : ''}">
                        <a class="page-link" th:href="@{/board/list(pageNo = ${i})}">[[${i}]]</a>
                    </li>
                </th:block>

                <li th:if="${pgvo.hasNext}" class="page-item">
                    <a class="page-link" th:href="@{/board/list(pageNo = ${pgvo.endPage + 1})}" aria-label="Next">
                        <span aria-hidden="true">&raquo;</span>
                    </a>
                </li>
            </ul>
        </nav>
    </div>
</div>

 

 PagingVO.java

package com.ezen.boot_JPA.dto;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.data.domain.Page;

@Getter
@Setter
@ToString
public class PagingVO {
    private int totalPage;
    private int startPage;
    private int endPage;
    private boolean hasPrev, hasNext;
    private int pageNo;

    public PagingVO(Page<BoardDTO> list, int pageNo){
        this.pageNo = pageNo + 1;
        this.totalPage = list.getTotalPages();

        this.endPage = (int)Math.ceil(this.pageNo / 10.0) * 10;
        this.startPage = endPage - 9;
        if(endPage > totalPage){
            endPage = totalPage;
        }
        this.hasPrev = this.startPage > 10;
        this.hasNext = this.endPage < this.totalPage;
    }
}

 

 BoardController.java

package com.ezen.boot_JPA.controller;

import com.ezen.boot_JPA.dto.BoardDTO;
import com.ezen.boot_JPA.dto.PagingVO;
import com.ezen.boot_JPA.service.BoardService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.util.List;

@Slf4j
@RequestMapping("/board/*")
@RequiredArgsConstructor
@Controller
public class BoardController {
    private final BoardService boardService;

    @GetMapping("/register")
    public void register(){}

    @PostMapping("/register")
    public String register(BoardDTO boardDTO){
        log.info(">>> boardDTO >>> {}", boardDTO);
        // insert, update, delete => return 1 row
        // jpa insert, update, delete => return id
        Long bno = boardService.insert(boardDTO);
        log.info(">>> insert >>> {}", bno > 0 ? "OK" : "FAIL");
        return "/index";
    }

    /*@GetMapping("/list")
    public void list(Model model){
        // paging이 없는 케이스
        List<BoardDTO> list = boardService.getList();
        model.addAttribute("list", list);
    }*/

    @GetMapping("/list")
    public void list(Model model, @RequestParam(value = "pageNo", defaultValue = "0", required = false) int pageNo){
        // 화면에서 들어오는 pageNo = 1 / 0으로 처리가 되어야 함
        // 화면에서 들어오는 pageNo = 2 / 1로 처리가 되어야 함
        log.info(">>> pageNo >>> {}", pageNo);
        pageNo = (pageNo == 0 ? 0 : pageNo - 1);
        log.info(">>> pageNo >>> {}", pageNo);
        Page<BoardDTO> list = boardService.getList(pageNo);

        log.info(">>> list >>> {}", list.toString());
        log.info(">>> totalCount >>> {}", list.getTotalElements()); // 전체 글 수
        log.info(">>> totalPage >>> {}", list.getTotalPages()); // 전체 페이지 수 => realEndPage
        log.info(">>> pageNumber >>> {}", list.getNumber()); // 전체 페이지 번호 => pageNo
        log.info(">>> pageSize >>> {}", list.getSize()); // 한 페이지에 표시되는 길이 => qty
        log.info(">>> next >>> {}", list.hasNext()); // next 여부
        log.info(">>> prev >>> {}", list.hasPrevious()); // prev 여부

        PagingVO pgvo = new PagingVO(list, pageNo);
        log.info(">>> pgvo >>> {}", pgvo.toString());
        model.addAttribute("list", list);
        model.addAttribute("pgvo", pgvo);
    }

    @GetMapping("/detail")
    public void modify(Model model, @RequestParam("bno") Long bno){
        BoardDTO boardDTO = boardService.getDetail(bno);
        model.addAttribute("boardDTO", boardDTO);
    }

    @PostMapping("/modify")
    public String modify(BoardDTO boardDTO, RedirectAttributes redirectAttributes){
        Long bno = boardService.modify(boardDTO);
        redirectAttributes.addAttribute("bno", boardDTO.getBno());
        return "redirect:/board/detail";
    }

    @GetMapping("/delete")
    public String delete(@RequestParam("bno") Long bno){
        boardService.delete(bno);
        return "redirect:/board/list";
    }
}

 

 BoardService.java

package com.ezen.boot_JPA.service;

import com.ezen.boot_JPA.dto.BoardDTO;
import com.ezen.boot_JPA.entity.Board;
import org.springframework.data.domain.Page;

import java.util.List;

public interface BoardService {
    // 추상 메서드만 가능한 인터페이스
    // 메서드가 default(접근제한자) 구현 가능
    Long insert(BoardDTO boardDTO);

    // BoardDTO(class): bno title writer content regAt modAt
    // Board(table) : bno title writer content
    // BoardDTO => board 변환
    // 화면에서 가져온 BoardDTO 객체를 저장을 위한 Board 객체로 변환
    default Board convertDtoToEntity(BoardDTO boardDTO){
        return Board.builder()
                .bno(boardDTO.getBno())
                .title(boardDTO.getTitle())
                .writer(boardDTO.getWriter())
                .content(boardDTO.getContent())
                .build();
    }

    // board => BoardDTO 변환
    // DB에서 가져온 Board 객체를 화면에 뿌리기 위한 BoardDTO 객체로 변환
    default BoardDTO convertEntityToDto(Board board){
        return BoardDTO.builder()
                .bno(board.getBno())
                .title(board.getTitle())
                .writer(board.getWriter())
                .content(board.getContent())
                .regAt(board.getRegAt())
                .modAt(board.getModAt())
                .build();
    }

//  List<BoardDTO> getList();

    Page<BoardDTO> getList(int pageNo);

    BoardDTO getDetail(Long bno);

    Long modify(BoardDTO boardDTO);

    void delete(Long bno);

}

 

 BoardServiceImpl.java

package com.ezen.boot_JPA.service;

import com.ezen.boot_JPA.dto.BoardDTO;
import com.ezen.boot_JPA.entity.Board;
import com.ezen.boot_JPA.repository.BoardRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Slf4j
@RequiredArgsConstructor
@Service
public class BoardServiceImpl implements BoardService{
    private final BoardRepository boardRepository;

    @Override
    public Long insert(BoardDTO boardDTO) {
        // 저장 객체는 Board
        // save() : insert 후 저장 객체의 id를 리턴
        // save() Entity 객체를 파라미터로 전송
        return boardRepository.save(convertDtoToEntity(boardDTO)).getBno();
    }

//    @Override
//    public List<BoardDTO> getList() {
//        // 컨트롤러로 보내야 하는 리턴은 List<BoardDTO>
//        // DB에서 가져오는 리턴은 List<Board> > BoardDTO 객체로 변환
//        // findAll()
//        // 정렬 : Sort.by(Sort.Direction.DESC, "정렬기준 칼럼명")
//        List<Board> boardList = boardRepository.findAll(Sort.by(Sort.Direction.DESC, "bno"));
//        /* List<BoardDTO> boardDTOList = new ArrayList<>();
//        for(Board board : boardList){
//            boardDTOList.add(convertEntityToDto(board));
//        }*/
//        List<BoardDTO> boardDTOList = boardList.stream()
//                .map(b -> convertEntityToDto(b)).toList();
//        return boardDTOList;
//    }

    @Override
    public Page<BoardDTO> getList(int pageNo) {
        // pageNo = 0부터 시작
        // 0 => limit 0, 10 / 1 => limit 10, 10
        Pageable pageable = PageRequest.of(pageNo, 10,
                Sort.by("bno").descending());
        Page<Board> list = boardRepository.findAll(pageable);
        Page<BoardDTO> boardDTOList = list.map(b -> convertEntityToDto(b));
        return boardDTOList;
    }

    @Override
    public BoardDTO getDetail(Long bno) {
        /* findById : 아이디(PK)를 주고 해당 객체를 리턴
            findById의 리턴타입 Optional<Board> 타입으로 리턴
            Optional<T> : nullPointException이 발생하지 않도록 도와줌.
            Optional.isEmpty() : null일 경우 확인 가능 true / false
            Optional.isPresent() : 값이 있는지 확인 true / false
            Optional.get() : 객체 가져오기
        * */
        Optional<Board> optional = boardRepository.findById(bno);
        if(optional.isPresent()){
            BoardDTO boardDTO = convertEntityToDto(optional.get());
            return boardDTO;
        }
        return null;
    }

    @Override
    public Long modify(BoardDTO boardDTO) {
        // update : jpa는 업데이트가 없음.
        // 기존 객체를 가져와서 set 수정 후 다시 저장
        Optional<Board> optional = boardRepository.findById(boardDTO.getBno());
        if(optional.isPresent()){
            Board entity = optional.get();
            entity.setTitle(boardDTO.getTitle());
            entity.setContent(boardDTO.getContent());
            // 다시 저장 (기존 객체에 덮어쓰기)
            return boardRepository.save(entity).getBno();
        }
        return null;
    }

    // 삭제 : deleteById(id)

    @Override
    public void delete(Long bno) {
        boardRepository.deleteById(bno);
    }

}

 

출력

 

2. comment

 detail.html

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/layout}">

<div layout:fragment="content">
    <div class="container-md">
        <h1>Board Detail Page [[boardDTO.bno]]</h1>

        <form action="/board/modify" method="post" id="modForm">
            <div class="mb-3">
                <label for="r" class="form-label">Created At</label>
                <input type="text" class="form-control" name="regDate" id="r" th:value="${boardDTO.regAt}" readonly>
            </div>
            <div class="mb-3">
                <input type="hidden" class="form-control" name="bno" id="n" th:value="${boardDTO.bno}">
            </div>
            <div class="mb-3">
                <label for="title" class="form-label">Title</label>
                <input type="text" class="form-control" name="title" id="title" th:value="${boardDTO.title}" readonly>
            </div>
            <div class="mb-3">
                <label for="writer" class="form-label">Writer</label>
                <input type="text" class="form-control" name="writer" id="writer" th:value="${boardDTO.writer}" readonly>
            </div>
            <div class="mb-3">
                <label for="content" class="form-label">Content</label>
                <textarea class="form-control" name="content" id="content" rows="3" readonly>[[${boardDTO.content}]]</textarea>
            </div>
            <button type="button" id="listBtn" class="btn btn-primary">List</button>
            <button type="button" id="modBtn" class="btn btn-warning">Modify</button>
            <a th:href="@{/board/delete(bno=${boardDTO.bno})}">
                <button type="button" id="delBtn" class="btn btn-danger">Delete</button>
            </a>
        </form>

        <!-- comment line -->
        <!-- post -->
        <div class="input-group mb-3" >
            <span class="input-group-text" id="cmtWriter"></span>
            <input type="text" id="cmtText" class="form-control" placeholder="Add Comment..." aria-label="Username" aria-describedby="basic-addon1">
            <button type="button" id="cmtAddBtn" class="btn btn-secondary">post</button>
        </div>
        <!-- spread -->
        <ul class="list-group list-group-flush" id="cmtListArea">
            <li class="list-group-item">
                <div class="ms-2 me-auto">
                    <div class="fw-bold">writer</div>
                    Content
                </div>
                <span class="badge text-bg-primary rounded-pill">regDate</span>
            </li>
        </ul>
        <!-- moreBtn-->
        <div>
            <button type="button" id="moreBtn" data-page="1" class="btn btn-dark" style="visibility:hidden">MORE + </button>
        </div>
        <!-- modal -->
        <div class="modal fade" id="myModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h1 class="modal-title fs-5" id="cmtWriterMod">${authNick }</h1>
                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <div class="modal-body">
                        <input type="text" class="form-control" id="cmtTextMod">
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
                        <button type="button" id="cmtModBtn" class="btn btn-primary">changes</button>
                    </div>
                </div>
            </div>
        </div>

        <script th:inline="javascript">
            let bnoVal = [[${boardDTO.bno}]]
            console.log(bnoVal);
        </script>

    </div>
    <script th:src="@{/js/boardDetail.js}"></script>
    <script th:src="@{/js/boardComment.js}"></script>

    <script>
        spreadCommentList(bnoVal);
    </script>
</div>

 

 boardComment.js

console.log("boardComment.js in");
console.log(bnoVal);

document.getElementById('cmtAddBtn').addEventListener('click',  ()=>{
    const cmtText = document.getElementById('cmtText');
    if(cmtText == null || cmtText == ''){
        alert('댓글 내용을 입력해주세요')
        cmtText.focus();
        return false;
    }
    const cmtData = {
        bno : bnoVal,
        writer : document.getElementById('cmtWriter').innerText,
        content : cmtText.value
    };
    postCommentToServer(cmtData).then(result => {
        if(result > 0){
            alert("댓글 등록 성공");
            cmtText.value = "";
        }
        // 댓글 뿌리기 호출
         spreadCommentList(bnoVal);
    })
});

async function postCommentToServer(cmtData) {
    try {
        const url = "/comment/post";
        const config = {
            method: "post",
            headers:{
                'Content-Type':'application/json; charset=utf-8'
            },
            body: JSON.stringify(cmtData)
        };
        const resp = await fetch(url, config);
        const result = await resp.text();
        return result;
    } catch (error) {
        console.log(error);
    }
}

function spreadCommentList(bno, page=1){
    getCommentListFromServer(bno, page).then(result =>{
        console.log(result);
        const ul = document.getElementById('cmtListArea');
        if(result.content.length > 0){
            if(page == 1){
                ul.innerHTML=""; // 기존 샘플값 비우기.
            }
            for(let cvo of result.content){
                console.log(cvo);
                let li = `<li data-cno = "${cvo.cno}" class="list-group-item">`;
                li += `<div class="ms-2 me-auto">`;
                li += `<div class="fw-bold">Anomyous</div>`;
                li += `${cvo.content}`;
                li += `</div>`;
                li += `<span class="badge text-bg-primary rounded-pill">${cvo.regDate}</span>`;
//                if(nickName == cvo.writer){
                    li += `<button type="button" class="btn btn-outline-warning btn-sm mod" data-bs-toggle="modal" data-bs-target="#myModal">%</button>`;
                    li += `<button type="button" class="btn btn-outline-danger btn-sm del">X</button>`;
//                }
                li += `</li>`;
                ul.innerHTML += li;
            }

            // page 처리
            let moreBtn= document.getElementById('moreBtn');
            // 전체 페이지가 현재 페이지보다 크다면... (나와야 할 페이지가 존재한다면...)
            if(page < result.totalPages){
                moreBtn.style.visibility = "visible"; // 표시
                moreBtn.dataset.page = page + 1;
            }else{
                moreBtn.style.visibility = "hidden"; // 숨김
            }

        }else{
            let li = `<li class="list-group-item">Comment List Empty</li>`;
            ul.innerHTML = li;
        }
    });
};

async function getCommentListFromServer(bno, page) {
    try{
        const resp = await fetch("/comment/list/"+bno+"/"+page);
        const result = await resp.json();
        return result;
    } catch(error){
        console.log(error);
    }
}

document.addEventListener('click',(e)=> {
    if(e.target.id == 'moreBtn'){
        let page = parseInt(e.target.dataset.page);
        spreadCommentList(bnoVal, page);
    }
    if(e.target.classList.contains('del')){
        let cno = e.target.closest('li').dataset.cno;
        removeCommentToServer(cno).then(result => {
            if(result > 0){
                alert("삭제 성공!!");
                spreadCommentList(bnoVal);
            }
        })
    }
    if(e.target.classList.contains('mod')){
        let li = e.target.closest('li');
        let modWriter = li.querySelector(".fw-bold").innerText;
        document.getElementById('cmtWriterMod').innerText = modWriter;
        let cmtText =li.querySelector('.fw-bold').nextSibling; // 쿼리 값의 같은 부모의 다른 형제 값
        document.getElementById('cmtTextMod').value = cmtText.nodeValue; // 그냥 넣으면 Object로 입력
        
        // 수정 버튼 id = cmtModBtn dataset
        document.getElementById('cmtModBtn').setAttribute("data-cno", li.dataset.cno);
    }
    if(e.target.id == 'cmtModBtn'){
        let cmtModData={
            cno : e.target.dataset.cno,
            content : document.getElementById('cmtTextMod').value
        }
        console.log(cmtModData);

        // 비동기 처리
        updateCommentToServer(cmtModData).then(result =>{
            if(result > 0){
                alert("수정 성공!!");
            }
            // 모달창 닫기
            document.querySelector('.btn-close').click();
            spreadCommentList(bnoVal);
        });
    }
});

async function updateCommentToServer(cmtModData) {
    try{
        const url = "/comment/update"
        const config ={
            method : "put",
            headers : {
                'content-type':'application/json; charset=utf-8'
            },
            body : JSON.stringify(cmtModData)
        }
        const resp = await fetch(url, config);
        const result = await resp.text();
        return result;
    } catch(error){
        console.log(error);
    }
}

async function removeCommentToServer(cno) {
    try{
        const url = "/comment/remove/"+cno;
        const config={
            method:'get'
        }
        const resp = await fetch(url, config);
        const result = await resp.text();
        return result;
    } catch(error){
        console.log(error);
    }
}

 

 CommentDTO.java

package com.ezen.boot_JPA.dto;

import lombok.*;

import java.time.LocalDateTime;

@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CommentDTO {
    private long cno;
    private long bno;
    private String writer;
    private String content;
    private LocalDateTime regAt;
    private LocalDateTime modAt;
}

 

 Comment.java

package com.ezen.boot_JPA.entity;

import jakarta.persistence.*;
import lombok.*;

@Entity
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Comment extends TimeBase{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long cno;

    @Column(nullable = false)
    private long bno;

    @Column(length = 200, nullable = false)
    private String writer;

    @Column(length = 1000, nullable = false)
    private String content;
}

 

 CommentController.java

package com.ezen.boot_JPA.controller;

import com.ezen.boot_JPA.dto.CommentDTO;
import com.ezen.boot_JPA.service.CommentService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/comment/*")
@RequiredArgsConstructor
@Slf4j
public class CommentController {
    private final CommentService commentService;

    @PostMapping("/post")
    @ResponseBody
    public String post(@RequestBody CommentDTO commentDTO){
        long cno = commentService.post(commentDTO);
        return cno > 0 ? "1" : "0";
    }

    @GetMapping("/list/{bno}/{page}")
    @ResponseBody
    public Page<CommentDTO> list(@PathVariable("bno") long bno, @PathVariable("page") int page){
        // page = 0부터
        // 1 page => 0 / 2 page => 1
        page = (page == 0 ? 0 : page - 1);
//        List<CommentDTO> list = commentService.getList(bno);
        Page<CommentDTO> list = commentService.getList(bno, page);
        log.info(">>> list >>> {}", list);
        return list;
    }

    @PutMapping("/update")
    @ResponseBody
    public String update(@RequestBody CommentDTO commentDTO){
        long cno = commentService.update(commentDTO);
        return cno > 0 ? "1" : "0";
    }

    @GetMapping("/remove/{cno}")
    public long remove(@PathVariable("cno") long cno){
        long isOk = commentService.remove(cno);
        return isOk > 0 ? 1 : 0;
    }

}

 

 CommentService.java

package com.ezen.boot_JPA.service;

import com.ezen.boot_JPA.dto.CommentDTO;
import com.ezen.boot_JPA.entity.Comment;
import org.springframework.data.domain.Page;

import java.util.List;

public interface CommentService {
    long post(CommentDTO commentDTO);

    // convert 작업
    // DTO => Entity
    default Comment convertDtoToEntity(CommentDTO commentDTO){
        return Comment.builder()
                .cno(commentDTO.getCno())
                .bno(commentDTO.getBno())
                .writer(commentDTO.getWriter())
                .content(commentDTO.getContent())
                .build();
    }

    default CommentDTO convertEntityToDto(Comment comment) {
        return CommentDTO.builder()
                .cno(comment.getCno())
                .bno(comment.getBno())
                .writer(comment.getWriter())
                .content(comment.getContent())
                .build();
    }

//    List<CommentDTO> getList(long bno);

    Page<CommentDTO> getList(long bno, int page);

    long remove(long cno);

    long update(CommentDTO commentDTO);
}

 

 CommentServiceImpl.java

package com.ezen.boot_JPA.service;

import com.ezen.boot_JPA.dto.CommentDTO;
import com.ezen.boot_JPA.entity.Comment;
import com.ezen.boot_JPA.repository.CommentRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
@RequiredArgsConstructor
@Slf4j
public class CommentServiceImpl implements CommentService{
    private final CommentRepository commentRepository;

    @Override
    public long post(CommentDTO commentDTO) {
        return commentRepository.save(convertDtoToEntity(commentDTO)).getBno();
    }

//    @Override
//    public List<CommentDTO> getList(long bno) {
//        // select * from comment where bno = ${bno}
//        List<Comment> list = commentRepository.findByBno(bno);
//        List<CommentDTO> dtoList = list.stream().map(c -> convertEntityToDto(c)).toList();
//        return dtoList;
//    }

    @Override
    public Page<CommentDTO> getList(long bno, int page) {
        Pageable pageable = PageRequest.of(page, 5, Sort.by("cno").descending());
        Page<Comment> list = commentRepository.findByBno(bno, pageable);
        Page<CommentDTO> dtoPageList = list.map(c -> convertEntityToDto(c));
        return dtoPageList;
    }

    @Override
    public long update(CommentDTO commentDTO) {
        Optional<Comment> optionalComment = commentRepository.findById(commentDTO.getCno());
        if(optionalComment.isPresent()){
            Comment comment = optionalComment.get();
            comment.setContent(commentDTO.getContent());
            return commentRepository.save(comment).getCno();
        }
        return 0;
    }

    @Override
    public long remove(long cno) {
        Optional<Comment> comment = commentRepository.findById(cno);
        if(comment.isPresent()) {
            commentRepository.deleteById(cno);
            return 1;
        }else {
            return 0;
        }
    }
}

 

 CommentRepository.java

package com.ezen.boot_JPA.repository;

import com.ezen.boot_JPA.entity.Comment;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

/* JpaRepository<entity name, id class> */
public interface CommentRepository extends JpaRepository<Comment, Long> {
//    List<Comment> findByBno(long bno);
    Page<Comment> findByBno(long bno, Pageable pageable);
}

 

출력