You can easily implement screen paging functionality with Spring Boot + Thymeleaf.
Screen image after completion

@Entity
@Table(name="word_info")
public class Word implements Serializable {
	private static final long serialVersionUID = -870708489937857961L;
	
	@Id
	@GeneratedValue(strategy=GenerationType.TABLE, generator="seqTable")
	@TableGenerator(name="seqTable", table="seq_table", pkColumnName="seq_name", pkColumnValue="word_seq", valueColumnName="seq_value")
	@Column(name="id")
	private Long id;
	
	@Column(name="word")
	private String word;
	
	@Column(name="meaning")
	private String meaning;
	
	@Column(name="example")
	private String example;
	//get / set omitted
	...
}
Define a JPA repository class to get the list. Use the Page class instead of List.
@Repository
public interface WordRepository extends CrudRepository<Word, Long>{
	
	public Page<Word> findAll(Pageable pageable);
}
@Service
public class WordService {
	
	@Autowired
	private WordRepository wordRepo;
	
	public Page<Word> getAllWord(Pageable pageable) {
		return wordRepo.findAll(pageable);
	}
}
@Controller
public class MainController {
	
	@Autowired
	private WordService wordService;
	
	@RequestMapping(value="/word/wordList", method=RequestMethod.GET)
	public String getWordList(Model model, Pageable pageable) {
		Page<Word> wordsPage = wordService.getAllWord(pageable);
		model.addAttribute("page", wordsPage);
		model.addAttribute("words", wordsPage.getContent());
		model.addAttribute("url", "/word/wordList");
		
		return "/word/wordList";
	}
}
Set the maximum number of items to be displayed for each page.
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
  @Override
  public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
      PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver();
      //Number of items to be displayed per page
      resolver.setFallbackPageable(new PageRequest(0, 5));
      argumentResolvers.add(resolver);
      super.addArgumentResolvers(argumentResolvers);
  }
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	  xmlns:th="http://www.thymeleaf.org">
	<head>
		<meta charset="UTF-8" />
		<link th:substituteby="common/header :: common_header"/>
		<title>Word List</title>
	</head>
	<body>
		<table border="1">
			<tr>
				<th>ID</th>
				<th>WORD</th>
				<th>MEANING</th>
				<th>EXAMPLE</th>
			</tr>
			<tr th:each="word:${words}">
				<td th:text="${word.id}"></td>
				<td th:text="${word.word}"></td>
				<td th:text="${word.meaning}"></td>
				<td th:text="${word.example}"></td>
			</tr>
		</table>
		
		<div th:fragment='paginationbar'>
			<ul>
				<li th:class="${page.first} ? 'disabled':''" style="display:inline">
					<span th:if="${page.first}">← First</span>
					<a th:if="${not page.first}" th:href="@{${url}(page=0)}">← First</a>
				</li>
				<li th:each='i : ${#numbers.sequence(0, page.totalPages-1)}' th:class="(${i}==${page.number})? 'active' : ''" style="display:inline">
                	<span th:if='${i}==${page.number}' th:text='${i+1}'>1</span>
               	 	<a th:if='${i}!=${page.number}' th:href="@{${url}(page=${i})}">
               	 		<span th:text='${i+1}'>1</span>
               	 	</a>
                </li>
				<li th:class="${page.last} ? 'disabled':''" style="display:inline">
					<span th:if="${page.last}">End ➝</span>
					<a th:if="${not page.last}" th:href="@{${url}(page=(${page.totalPages}-1))}">End ➝</a>
				</li>
			</ul>
		</div>
	</body>
</html>
In the case where the number of pages is large as shown below, if you want to display only some page numbers, you can create a wrapper class for Page and customize it.

public class PageWrapper<T> {
    public static final int MAX_PAGE_ITEM_DISPLAY = 5;
    private Page<T> page;
    private List<PageItem> items;
    private int currentNumber;
    private String url;
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public PageWrapper(Page<T> page, String url){
        this.page = page;
        this.url = url;
        items = new ArrayList<PageItem>();
        currentNumber = page.getNumber() + 1;
        int start, size;
        if (page.getTotalPages() <= MAX_PAGE_ITEM_DISPLAY){
            start = 1;
            size = page.getTotalPages();
        } else {
            if (currentNumber <= MAX_PAGE_ITEM_DISPLAY - MAX_PAGE_ITEM_DISPLAY/2){
                start = 1;
                size = MAX_PAGE_ITEM_DISPLAY;
            } else if (currentNumber >= page.getTotalPages() - MAX_PAGE_ITEM_DISPLAY/2){
                start = page.getTotalPages() - MAX_PAGE_ITEM_DISPLAY + 1;
                size = MAX_PAGE_ITEM_DISPLAY;
            } else {
                start = currentNumber - MAX_PAGE_ITEM_DISPLAY/2;
                size = MAX_PAGE_ITEM_DISPLAY;
            }
        }
        for (int i = 0; i<size; i++){
            items.add(new PageItem(start+i, (start+i)==currentNumber));
        }
    }
    public List<PageItem> getItems(){
        return items;
    }
    public int getNumber(){
        return currentNumber;
    }
    public List<T> getContent(){
        return page.getContent();
    }
    public int getSize(){
        return page.getSize();
    }
    public int getTotalPages(){
        return page.getTotalPages();
    }
    public boolean isFirstPage(){
        return page.isFirst();
    }
    public boolean isLastPage(){
        return page.isLast();
    }
    public boolean isHasPreviousPage(){
        return page.hasPrevious();
    }
    public boolean isHasNextPage(){
        return page.hasNext();
    }
    public class PageItem {
        private int number;
        private boolean current;
        public PageItem(int number, boolean current){
            this.number = number;
            this.current = current;
        }
        public int getNumber(){
            return this.number;
        }
        public boolean isCurrent(){
            return this.current;
        }
    }
}
Use the wrapper class instead of Page.
@Controller
public class MainController {
	
	@Autowired
	private WordService wordService;
	@RequestMapping("/word/register")
	public String wordRegister(WordForm wordForm) {
		wordService.addWord(wordForm);
		return "/word/wordRegister";
	}
	
	@RequestMapping(value="/word/wordList", method=RequestMethod.GET)
	public String getWordList(Model model, Pageable pageable) {
		Page<Word> wordPage = wordService.getAllWord(pageable);
		PageWrapper<Word> page = new PageWrapper<Word>(wordPage, "/word/wordList");
		model.addAttribute("page", page);
		model.addAttribute("words", page.getContent());
		
		return "/word/wordList";
	}
}
Thymeleaf
Change the paging part as follows.
	...
		<div th:fragment='paginationbar'>
			<ul class='pagination pagination-centered'>
				<li th:class="${page.firstPage}?'disabled':''" style="display:inline">
					<span th:if='${page.firstPage}'>← First</span>
					<a th:if='${not page.firstPage}' th:href='@{${page.url}(page=0,size=${page.size})}'>← First</a>
				</li>
				<li th:class="${page.hasPreviousPage}? '' : 'disabled'" style="display:inline">
					<span th:if='${not page.hasPreviousPage}'>«</span>
					<a th:if='${page.hasPreviousPage}' th:href='@{${page.url}(page=${page.number-2},size=${page.size})}'>«</a>
				</li>
	                
	                
				<li th:each='item : ${page.items}' th:class="${item.current}? 'active' : ''" style="display:inline">
					<span th:if='${item.current}' th:text='${item.number}'>1</span>
					<a th:if='${not item.current}' th:href='@{${page.url}(page=${item.number-1},size=${page.size})}'>
					<span th:text='${item.number}'>1</span>
					</a>
				</li>
				<li th:class="${page.hasNextPage}? '' : 'disabled'" style="display:inline">
					<span th:if='${not page.hasNextPage}'>»</span>
					<a th:if='${page.hasNextPage}' th:href='@{${page.url}(page=${page.number},size=${page.size})}'>»</a>
				</li>
				<li th:class="${page.lastPage}? 'disabled' : ''" style="display:inline">
					<span th:if='${page.lastPage}'>End ➝</span>
					<a th:if='${not page.lastPage}' th:href='@{${page.url}(page=${page.totalPages - 1},size=${page.size})}'>End ➝</a>
				</li>
			</ul>
		</div>
	...
Reference: https://github.com/mtiger2k/pageableSpringBootDataJPA
Recommended Posts