Merhabalar arkadaşlar, bu yazıda size Rest API üzerinde Pagination işleminin nasıl yapıldığını Spring Boot tabanlı bir proje ile anlatacağım.

Bu yazıdaki uygulamanın kaynak kodlarına https://github.com/ilkgunel/RestPagination adresinden erişebilirsiniz.

Kodlar üzerinden bu işlemin nasıl yapılabileceğine birlikte bakmadan önce veritabanındaki kayıtlara değinelim. Benim characters tablomda aşağıdaki görüntüdeki gibi 6 adet kayıt yer alıyor ve listeleme işlemleri için de bu kayıtları kullanacağız.

Şimdi kodlara değinelim.

Characters.java

package com.ilkaygunel.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "CHARACTERS")
public class Characters {
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private long characterId;
	
	@Column
	private String characterName;
	
	@Column
	private String characterSurname;

	public long getCharacterId() {
		return characterId;
	}

	public void setCharacterId(long characterId) {
		this.characterId = characterId;
	}

	public String getCharacterName() {
		return characterName;
	}

	public void setCharacterName(String characterName) {
		this.characterName = characterName;
	}

	public String getCharacterSurname() {
		return characterSurname;
	}

	public void setCharacterSurname(String characterSurname) {
		this.characterSurname = characterSurname;
	}	
}

Characters sınıfı bizim veritabanımızdaki Characters tablomuza karşılık gelen entity sınıfımızdır. Characters tablomuz da id, name, surname bilgilerini tutan bir tablodur.

CharacterDao.java

package com.ilkaygunel.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;

import com.ilkaygunel.entity.Characters;

@Repository
public interface CharacterDao extends CrudRepository<Characters, Long> {
	Page<Characters> findAll(Pageable pageable);
}

CharacterDao interface’imiz bizim Spring Data içerisindeki CrudRepository interface’ini kalıtarak oluşturduğumuz bir interface’dir. Kalıtma sırasında CrudRepository’e geçirilen parametrelerden birisi bu sınıf hangi entity’e bağlı olacak, ikincisi de o entity’nin primary key alanının tipi nedir sorularına cevap olacak şekildedir. CharacterDao interface’ini biz Characters sınıfı için yazdık ve Characters sınıfının primary key alanı da Long veri tipinde. Interface içerisinde de kendimiz custom bir metot tanımı yaptık. Bu custom metodun içinin doldurulması görevi Spring Data’ya aittir. Bizim için Pageable tipinde parametre alan Page tipinde veri dönen findAll metodu Spring Data tarafından oluşturulacaktır.

CharacterService.java

package com.ilkaygunel.service;

import com.ilkaygunel.entity.Characters;
import com.ilkaygunel.exception.ResourceNotFoundException;
import com.ilkaygunel.repository.CharacterDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

@Service
public class CharacterService {

    @Autowired
    private CharacterDao characterDao;

    public Page<Characters> getPaginatedCharacters(int pageNumber) {
        PageRequest pageable = PageRequest.of(pageNumber - 1, 2);
        Page<Characters> resultPage = characterDao.findAll(pageable);
        if (pageNumber > resultPage.getTotalPages()) {
            throw new ResourceNotFoundException("Not Found Page Number:" + pageNumber);
        }
        return resultPage;
    }
}

CharacterService sınıfımıza az önce yazdığımız CharacterDao interface’ini @AutoWired ile inject ediyoruz. Akabinde int veri tipindeki pageNumber’ı parametre alan getPaginatedCharacters metodumuz öncelikle gelen pageNumber parametresi ile PageRequest tipindeki pageable nesnesini oluşturuyor. PageRequest.of(pageNumber - 1, 2); ifadesineki birinci parametre gelen pageNumber parametresinin 1 azaltılmış halidir. Burada programlama dillerinde bildiğimiz klasik Array’in 0. gözden başlaması mantığı vardır. ikinci parametre ise ilgili page’de ne kadar kayıt getirileceğini söyleyen bir parametredir. 2 değerini parametre olarak geçerek her sayfada 2 kayıt getirilmesini istemiş olduk.characterDao.findAll(pageable); ifadesi ile de gelen pageNumber’daki 2 kaydı çekip resultPage nesnesine atıyoruz ve eğer parametre olarak gelen sayfa numarası bizim kayıtlarımızın 2’şerli şekilde gruplandığı sayfa sayısından büyük olursa ResourceNotFoundException hatası fırlatıyoruz. Eğer bir sorun yok ise de resultPAge nesnesini dönüyoruz.

CharacterRestController.java

package com.ilkaygunel.controller;

import com.ilkaygunel.entity.Characters;
import com.ilkaygunel.service.CharacterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/")
public class CharacterRestController {

	@Autowired
	private CharacterService characterService;

	@GetMapping("characters")
	@ResponseBody
	public List<Characters> findAllPaginated(@RequestParam("pageNumber") int pageNumber) {
		Page<Characters> resultPage = characterService.getPaginatedCharacters(pageNumber);
		return resultPage.getContent();
	}
}

CharacterRestController sınıfımız bir web servis isteğimizi karşılayacak metotları barındıracak olan sınıftır. Sınıf içerisinde az önce yazdığımız CharacterService sınıfımızı @Autowired ile Inject ediyoruz. @GetMapping(“characters”) ile characters path’ine gelecek GET isteğini findAllPaginated metodunun karşılayacağını söylüyoruz. /characters web servisi pageNumber URI’dan RequestParam olarak geçirilerek çağırılacak bir web servistir. Gelen pageNumber servis sınıfındaki getPaginatedCharacters metoduna geçiriliyor ve o da bize Page tipinde sonucu dönüyor. Biz de onun içinden content'i dönüyoruz.

Şimdi Application sınıfı üzerinden uygulamayı çalıştıralım ve Postman üzerinden uygulamamıza istekler gönderelim:

http://localhost:8080/RestPagination/characters?pageNumber=1 adresine bir GET isteği gönderdiğim zaman request’teki 1 değerinden dolayı bana veritabanındaki ilk 2 kayıtı getirmiş olacak.

Request’teki pageNumber’ı 3 yaptığım zaman da bana son 2 kaydı getirecek.

Kayıt sayısını aşacak şekilde bir sayfa numarası gönderdiğim takdirde de bana 404 HTTP kodu ile bir hata dönecek. Örneğin sayfa numarasını 5 olarak gönderdiğimizde bu hatayı alacağız.

Bu yazıda anlatacaklarım da bu kadar arkadaşlar. Bir sonraki yazıda görüşmek üzere.

Görüşene kadar sağlıcakla kalın.