1. 내비게이션 바 추가
1) 내비게이션 바 만들기
내비게이션 바
- 모든 화면 위쪽에 고정되어 있는 부트스트랩의 컴포넌트 중 하나
templates/layout.html
- <li>태그를 활용하여 내비게이션 바에 메뉴 추가 가능
...
<nav class="navbar navbar-expand-lg navbar-light bg-light border-bottom">
<div class="container-fluid">
<a class="navbar-brand" href="/">SBB</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="#">로그인</a>
</li>
</ul>
</div>
</div>
</nav>
...
2) 햄버거 메뉴
- 브라우저의 가로 사이즈를 마우스를 이용해 점점 줄이면 햄버거 메뉴 버튼이 생김
- 로그인 링크는 사라짐
- 부트스트랩은 브라우저의 크기가 작아지면 자동으로 내비게이션 바에 있는 링크들을 햄버거 메뉴 버튼으로 숨김
- 햄버거 메뉴 버튼을 활용할 수 있도록 부트스트랩 자바스크립트 파일(bootstrap.map.js)을 static 디렉터리로 복사
- 자바스크립트 파일을 사용할 수 있도록 layout.html 수정
3) 내비게이션 바 분리하기
- 내비게이션 바도 공통 템플릿으로 활용
templates/navbar.html
- layout.html 수정
- 기존의 내비게이션 바 HTML 코드들을 삭제하고 navbar.html 템플릿을 타임리프의 th:replace 속성으로 layout.html 템플릿에 포함시킴
templates/layout.html
2. 페이징 기능 추가
- 질문 목록 화면에 페이징 기능 적용
페이징(paging)
- 입력된 정보나 데이터를 여러 페이지에 나눠 표시하고, 사용자가 페이지를 이동할 수 있게 하는 기능
1) 대량 테스트 데이터 만들기
- 스프링 부트의 테스트 프레임워크 이용
SbbApplicationTests.java
- 총 300개의 테스트 데이터를 생성하는 테스트 케이스 작성
package com.example.demo;
import com.example.demo.question.QuestionService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SbbApplicationTests {
@Autowired
private QuestionService questionService;
@Test
void testJpa() {
for(int i=0; i<=300; i++) {
String subject = String.format("테스트 데이터입니다.:[%03d]",i);
String content = "내용 없음";
this.questionService.create(subject,content);
}
}
}
- 로컬 서버를 중지하고 [Run->Run As->Junit Test]로 testJpa 메서드 실행
2) 페이징 구현하기
org.springframework.data.domain.Page | 페이징을 위한 클래스 |
org.springframework.data.domain.PageRequest | 현재 페이지와 한 페이지에 보여 줄 게시물 수 등을 설정하여 페이징을 요청하는 클래스 |
org.springframework.data.domain.Pageable | 페이징을 처리하는 인터페이스 |
QuestionRepository.java
package com.example.demo.question;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
public interface QuestionRepository extends JpaRepository<Question,Integer> {
Question findBySubject(String subject);
Question findBySubjectAndContent(String subject, String content);
List<Question> findBySubjectLike(String subject);
Page<Question> findAll(Pageable pageable);
}
- Pageable 객체를 입력받아 Page<Question> 타입 객체를 리턴하는 findAll 메서드 생성
QuestionSerivce.java
package com.example.demo.question;
...
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
@RequiredArgsConstructor
@Service
public class QuestionService {
private final QuestionRepository questionRepository;
public Page<Question> getList(int page) {
Pageable pageable = PageRequest.of(page, 10);
return this.questionRepository.findAll(pageable);
}
...
- getList 메서드는 정수 타입의 페이지 번호를 입력받아 해당 페이지의 Page 객체를 리턴하도록 변경
- PageRequest.of(page, 10)에서 page는 조회할 페이지의 번호이고 10은 한 페이지에 보여 줄 게시물의 개수
- 데이터 전체를 조회하지 않고 해당 페이지의 데이터만 조회하도록 쿼리 변경
QuestionController 변경
QuestionController.java
...
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.data.domain.Page;
@RequestMapping("/question")
@RequiredArgsConstructor
@Controller
public class QuestionController{
private final QuestionService questionService;
@GetMapping("/list")
public String list(Model model, @RequestParam(value="page", defaultValue="0")int page) {
Page<Question> paging = this.questionService.getList(page);
model.addAttribute("paging", paging);
return "question_list";
}
...
- http://localhost:8080/question/list?page=0와 같이 GET 방식으로 요청된 URL에서 page값을 가져오기 위함
- list 메서드의 매개변수로 @RequestParam(value="page", defaultValue="0") int page 추가
- URL에 매개변수로 page가 전달되지 않은 경우 기본값은 0으로 되도록 설정
질문 목록 템플릿 변경
- 컨트롤러에서 model 객체에 기존에 전달했던 이름인 'questionList' 대신 'paging'으로 전달하기 때문에 question_list.html 변경
templates/question_list.html
속성 | 설명 |
paging.isEmpty | 페이지의 존재 여부 |
paging.totalElements | 전체 게시물 개수 |
paging.totalPages | 전체 페이지 개수 |
paging.size | 페이지당 보여줄 게시물 개수 |
paging.number | 현재 페이지 번호 |
paging.hasPrevious | 이전 페이지의 존재 여부 |
paging.hasNext | 다음 페이지의 존재 여부 |
3) 페이지 이동 기능 추가하기
- 질문 목록 화면에서 페이지를 이동할 수 있는 링크 추가
templates/question_list.html
...
<!-- 페이징처리 시작 -->
<div th:if="${!paging.isEmpty()}">
<ul class="pagination justify-content-center">
<li class="page-item" th:classappend="${!paging.hasPrevious} ? 'disabled'">
<a class="page-link"
th:href="@{|?page=${paging.number-1}|}">
<span>이전</span>
</a>
</li>
<li th:each="page: ${#numbers.sequence(0, paging.totalPages-1)}"
th:classappend="${page == paging.number} ? 'active'"
class="page-item">
<a th:text="${page}" class="page-link" th:href="@{|?page=${page}|}"></a>
</li>
<li class="page-item" th:classappend="${!paging.hasNext} ? 'disabled'">
<a class="page-link" th:href="@{|?page=${paging.number+1}|}">
<span>다음</span>
</a>
</li>
</ul>
</div>
<!-- 페이징처리 끝 -->
<a th:href="@{/question/create}" class="btn btn-primary">질문 등록하기</a>
</div>
- pagination은 ui 요소 안에 있는 내용을 꾸밀 수 있고, page-item은 각 페이지 번호나 '이전', '다음' 버튼을 나타내도록 하고, page-link는 '이전','다음' 버튼에 링크를 나타냄
- 이전 페이지가 없는 경우에는 '이전' 링크가 비활성화 되도록 함
- th:each 속성을 사용해 전체 페이지 수만큼 반복하면서 해당 페이지로 이동할 수 있는 '이전', '다음' 링크를 생성
4) 페이지 이동 기능 완성하기
- 페이지 표시 제한 기능 구현
- 현재 페이지 기준으로 좌우 5개씩 페이지 번호가 표시되도록 만듬
templates/question_list.html
5) 최신순으로 데이터 조회하기
QuestionService.java
package com.example.demo.question;
import java.util.ArrayList;
import java.util.List;
...
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@RequiredArgsConstructor
@Service
public class QuestionService {
private final QuestionRepository questionRepository;
public Page<Question> getList(int page) {
List<Sort.Order>sorts = new ArrayList<>();
sorts.add(Sort.Order.desc("createDate"));
Pageable pageable = PageRequest.of(page, 10, Sort.by(sorts));
return this.questionRepository.findAll(pageable);
}
...
- 게시물을 역순(최신순)으로 조회하려면 PageRequest.of 메서드의 세 번째 매개변수에 Sort 객체를 전달해야 함
- 작성 일시(createDate)를 역순(Desc)으로 조회하려면 Sort.Order.desc("createDate")와 같이 작성
'SpringBoot' 카테고리의 다른 글
[Do it] 3장 스프링 부트 고급 기능 익히기(3) (1) | 2024.01.23 |
---|---|
[Do it] 3장 스프링 부트 고급 기능 익히기(2) (0) | 2024.01.23 |
[Do it] 스프링 부트 기본 기능 익히기(6) (1) | 2024.01.22 |
[Do it] 2장 스프링 부트 기본 기능 익히기(5) (0) | 2024.01.21 |
[Do it] 2장 스프링 부트 기본 기능 익히기 (4) (0) | 2024.01.21 |