[Spring Boot] 게시판 +

1. HTML 파일 생성


‘First’, ‘Next’, ‘►►’ 기능은 HTML 파일에서 제외됩니다.

<html layout:decorate="~{layout}">
   <div layout:fragment="content">
   
   <table class="table">
      <tr>
          <td>no</td>
          <td>title</td>
          <td>date</td>
          <td>name</td>
          <td>like</td>
          <td>read</td>
      </tr>
      
      <tr th:each="row : ${list}">
      //${list}: controller에서 mv에 list의 key/value 넣어줌
         <td th:text="${row.bno}"></td>      
         <td>  
         	<a th:href="http://jenny-s.m/@{/detail(bno=${row.bno})}" th:text="${row.b_title}"></a> 
         </td>   
         <td th:text="${#dates.format(row.b_date, 'yyyy-MM-dd HH:mm:ss')}"></td>      
         <td th:text="${row.member.member_name}"></td> <!
-- Member.java에 member클래스 안에 member_name이 있음 --> <td th:text="${row.b_like}"></td> <td th:text="${row.b_read}"></td> </tr> </table> <div th:if="${!
list.isEmpty()}"> <!
-- list가 비어있지 않다면 --> <ul class="pagination justify-content-center"> <li class="page-item" th:classappend="${!
list.hasPrevious} ? 'disabled'"><!
-- disabled: 부트스트랩 들어가면 먹는 기능 --> <a class="page-link" th:href="@{|?pageNo=${list.number}|}">이전</a> </li> <!
--1부터 list.totalPages까지 숫자 찍기--> <li class="page-item" th:each="page : ${#numbers.sequence(1, list.totalPages)}" th:if="${page >= list.number and page <= list.number+10}" th:classappend="${page == list.number} ? 'active'"><!
-- active: 부트스트랩 들어가면 먹는 기능 --> <a class="page-link" th:text="${page}" th:href="@{|?pageNo=${page}|}"></a><!
-- ${page}: each의 변수명 --> </li> <li class="page-item" th:classappend="${!
list.hasNext} ? 'disabled'"> <a class="page-link" th:href="@{|?pageNo=${list.number+2}|}">다음</a> </li> </ul> </div> <button class="btn btn-primary" onclick="location.href="http://jenny-s.write"">글쓰기</button> </div> </html>

맨 위!

* #숫자.시퀀스()
– Thymeleaf에서 숫자 시퀀스를 만드는 도우미 메서드입니다.


주어진 시작 번호와 끝 번호 사이의 일련 번호를 생성합니다.


– 위의 코드에서 1은 시작 번호이고 list.totalPages는 종료 번호입니다.

* ${페이지 == 목록.번호} ? ‘활동적인’
– page와 list.number가 동일한 경우 활성 클래스 추가
– 활성: 클래스 이름만. 일반적으로 활성 상태를 표시합니다(현재 표시된 메뉴 항목 또는 현재 활성 탭 등을 표시할 때).
– active라는 이름은 많은 개발자들이 공통적으로 사용하는 클래스 이름 중 하나입니다.

* th:each=”page : ${#numbers.sequence(1, list.totalPages)}”와 th:each=page : ${list.totalPages}”의 차이점은 무엇입니까?
– 전자: #numbers 개체에서 제공하는 sequence 함수를 사용하여 1에서 list.totalPages까지의 범위를 만듭니다.


만들다

  • 반복으로 요소, 각 번호를 페이지 변수에 할당
    – 후자: list.totalPages는 단일 숫자이므로 해당 값을 반복합니다.

    (단수일 경우 각각 불필요)
  • *#지불하다
    – 타임리프에서 제공하는 소모품
    – 숫자와 관련된 몇 가지 유용한 기능을 수행합니다.


    – 예. #numbers.sequence(from, to)는 지정된 범위의 정수 시퀀스를 반환합니다.

    2. 컨트롤러 만들기

    @RequiredArgsConstructor
    @Controller
    public class IndexController {
    //controller -> service -> repository -> DB
    	
    	@Autowired
    	private final IndexService indexService;
    	
    	@GetMapping("/board")
    	public ModelAndView board(@RequestParam(value="pageNo", defaultValue="1") int pageNo) { 
    		ModelAndView mv = new ModelAndView("board"); //board.html
    		
           		 //페이징 추가하기
    		Page<Board> list = this.indexService.boardList(pageNo);
                    //boardList 메서드에 pageNo라는 파라미터를 전달
                    //boardList 메서드는 페이지네이션을 적용한 게시글 리스트를 반환 
                    //pageNo는 조회할 페이지 번호를 나타냄
                    //즉,pageNo에 해당하는 페이지의 게시글 리스트를 조회하여 list 변수에 할당함
            
    		mv.addObject("list",list);
    		return mv;
    	}

    맨 위!

    * (@RequestParam(value=”pageNo”, defaultValue=”1″) int pageNo)
    – int pageNo: 매개변수로 사용

    HTML 파일에 전달된 태그입니다.


    – 하지만 없다

    HTML 파일에서 페이지가 없습니다값이 없습니다. 값이 없으면 defaultValue=”1″을 통해 기본값이 1로 설정됩니다.


    – 즉, 페이징(번호)의 시작은 1입니다.

    * 책 페이지
    – JPA에서 제공하는 인터페이스
    – 페이지가 매겨진 데이터를 처리하는 기능 제공
    – (측면 인터페이스) Iterable 인터페이스를 상속하고 페이징된 데이터를 반복할 수 있습니다.


    – 다양한 방법을 제공합니다.

    대표 getTotalPages(), getContent(), getNumber() 등
    – Pageble을 매개변수로 얻은 결과는 Page 형식이 됩니다.

    반환
    – Page 형태로 반환> 대부분의 행을 가져오기 때문에

    * 페이지
    – 여기는 찾고 있는 게시물 정보가 포함된 엔터티 클래스입니다.

    게시물의 제목, 내용, 작성 날짜 등의 정보를 필드로 가지고 있습니다.


    – 페이지 페이지에 표시할 게시물을 포함하는 개체입니다.

    즉, 페이징된 게시물 목록은 페이지 유형의 목록 변수에 저장됩니다.

    저장되었습니다.

    (Spring Data Jpa에서 제공하는 메소드)
    *페이징
    -페이징 정보와의 인터페이스(페이징 처리에 사용)
    – Spring JPA의 DB 쿼리에서 제한 쿼리를 쉽고 유연하게 사용 가능
    – JPA 사용 시 Pageable 타입의 변수를 자동으로 넘기면 JPA는 DB 접근 및 데이터 조회 시 자동으로 경계조건 데이터를 import한다.


    – PageRequest 클래스로 구현

    * @PageableDefault
    – Pageable 개체의 기본값 설정
    (컨트롤러의 Pageable 객체를 매개변수로 받는 메소드에서 주석을 사용하면
    API를 요청할 때 페이징 가능한 객체에 대한 매개변수를 전달하지 않고 페이징 가능한 유형 매개변수에 기본값이 자동으로 제공됩니다.


    – 기본 페이지 크기 및 정렬 순서와 같은 값을 설정할 수 있습니다.

    * getTotalElements()
    – 쿼리 결과의 총 데이터 수를 반환(총 항목 수)
    – Pageable의 조건으로 limit 키워드가 입력되지 않은 쿼리 결과의 개수입니다.

    한 가지 유의할 점은 모든 데이터가 아니라 쿼리 결과의 수만 검색된다는 것입니다.


    – 게시판 기능 사용하기 좋습니다.

    나. 데이터의 총 개수를 사용자에게 알리기 위해

    * getTotalPages()
    – 총 페이지 수를 반환합니다.


    – 쿼리를 통해 조회된 항목을 크기별로 페이징했을 때 반환되는 총 페이지 수입니다.


    – 이를 통해 손쉽게 사이드 버튼을 생성할 수 있습니다.

    * getSize()
    – 페이지 크기를 반환합니다.


    – 페이지는 요청된 전체 데이터를 특정 숫자로 나누고 특정 숫자의 크기로 구성됩니다.

    * getNumber()
    – 현재 페이지 번호 반환(0부터 시작)

    * getNumberOfElements()
    – 현재 페이지의 항목 수를 반환합니다.


    – 최대 크기만큼 나올 수 있습니다.

    3. 서비스 생성

    @Service
    @RequiredArgsConstructor //생성자기반 
    
    
    public class IndexService {
    //IndexService: 데이터베이스와의 상호작용을 위한 메서드를 포함하고, 
    //해당 메서드를 사용하여 (indexRepository를 통해)게시물 데이터를 가져오는 기능을 수행
    	
    	private final IndexRepository indexRepository;
    	private final MemberRepository memberRepository;
    
    	public Page<Board> boardList(int pageNo) {
    		List<Sort.Order> sort = new ArrayList<Sort.Order>(); 
            	//Sort 객체는 JPA에서 데이터를 조회할 때, 정렬을 위해 사용됩니다.

    Order는 정렬 순서를 정하는 클래스 sort.add(Sort.Order.desc("bno")); //JPA는 _를 인식못함 //이 컬럼기준 역순정렬 //1부터 시작하기 위해 Pageable pageable = PageRequest.of(pageNo -1, 10,Sort.by(sort)); //pageNo:controller에서 defaultValue="1"로 설정해놔서 값은1. pageble은 0부터 셀수있도록 pageNo -1로 설정 //10개씩 출력 return this.indexRepository.findAll(pageable); //select기능 //pageble을 repository로 보내기 //findAll(): 데이터베이스에 저장된 모든 게시물을 가져온 후, 이를 List<BoardDTO> 형태로 반환 //모든 엔티티 레코드를 조회하기 위한 메서드. 리턴 타입은 해당 엔티티의 리스트 }

    맨 위!

    * @RequiredArgsConstructor와 @Autowired의 차이점
    : 두 설명 모두 Spring Framework에서 제공하는 Dependency Injection과 관련이 있습니다.

    (@RequiredArgsConstructor)
    – 생성자를 자동으로 생성하는 Lombok 주석
    – 이 주석이 있는 클래스의 생성자는 클래스에서 최종으로 선언된 필드만 매개변수로 받습니다.


    – 이 경우 생성자를 직접 작성하는 것보다 코드를 간결하게 작성할 수 있습니다.


    (@Autowired)
    – Spring 컨테이너에서 관리하는 Bean 아래에 적절한 타입의 Bean을 자동으로 주입하는 Annotation
    – 이 Annotation이 있는 필드나 생성자의 파라미터에 해당하는 Bean이 존재하지 않으면 에러가 발생한다.

    즉, @RequiredArgsConstructor는 자동 생성자 생성을 위한 주석입니다.

    @Autowired는 의존성 주입을 위한 주석입니다.

    * 목록 정렬 = newArrayList();
    – Sort.Order: 정렬 조건을 목록에 삽입하기 위한 객체
    – 정렬: 정렬 조건을 나타내는 클래스. JPA에서 제공하는 findAll 메소드를 호출하면 데이터 정렬이 가능하다.

    * PageRequest.of(pageNo -1, 10,Sort.by(정렬));
    : 정렬 목록에 지정된 속성별로 정렬하여 pageNoth 페이지에 10개의 게시물을 표시합니다.


    – Pageable을 구현하는 개체를 만듭니다.


    – 첫 번째 인수: 찾을 페이지 번호(pageNo)에서 1을 뺍니다.


    – 두 번째 인수: 페이지당 표시할 게시물 수
    – 마지막 인수: 정렬 방법을 지정하는 정렬 객체

    * Sort.by(속성)
    – 특정 속성을 기준으로 정렬하는 Sort 개체를 만듭니다.

    4. 저장소 생성

    public interface IndexRepository extends JpaRepository<Board,Integer> { 
    //JpaRepository<사용될entity클래스,ID값> 
    //ID는 repository에서 @ID로 설정
    
    	Page<Board> findAll(Pageable pageable); //Pageable : service에서 가져옴
    	//Board:(@Entity있는 dto역할)
    	//findTop5() : 5개만 조회
    }

    맨 위!

    – JpaRepository만 상속하면 되므로 @Repository를 선언할 필요가 없습니다.

    *Jpa저장소
    인터페이스를 통해 CRUD(만들기, 읽기, 업데이트, 삭제) 작업을 수행할 수 있습니다.


    – PagingAndSortingRepository 및 CrudRepository 인터페이스 상속
    – findAll(), findById(), save() 및 delete()와 같은 메소드를 자동으로 지원합니다.

    * 모두 찾기()
    – 모든 엔터티 레코드를 가져오는 방법
    – 반환 유형: 해당 엔터티 목록

    5. 보드 엔티티 생성
    (질문하는 역할)

    @Getter
    @Setter
    @Entity //@Entity는 JPA에서 Entity 클래스임을 나타내는 어노테이션
    @Table(name="board")
    public class Board { 	
    	
       @Id 
       @Column(name="b_no") //컬럼명 
       //JPA는 _를 인식못해서, 컬럼명의 _빼고 bno로 변수지정(b_no -> bno)
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       private int bno; //b_no의 변수명
    }

    맨 위!

    * 수업 게시판
    – 보드는 테이블 이름입니다.


    – 클래스명이 테이블명과 다를 경우 @Table(name=”board”)로 매핑
    – board.class의 int bno

    * @ID
    – 필드가 기본 키임을 나타냅니다.


    – In repository는 JpaRepository의 정수입니다.

    ID를 직접 입력하는 필드(@Id로 불러옴)

    * @Created값()
    – ID 값을 따로 설정하지 않으면 자동으로 ID 값(래퍼 클래스: 정수 등)을 호출
    – 기본 키 값 생성 전략에 대한 참고 사항

    * (전략 = GenerationType.IDENTITY)
    – MySQL에서 자동 증가 값을 사용한다는 의미

    참조

    https://velog.io/@albaneo0724/Spring-Pagination%EA%B3%BC-Page-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Pageable