Paginacija s Spring REST i AngularJS tablicom

OSTALO Vrh

Upravo sam najavio novo Uči proljeće tečaj, usredotočen na osnove Spring 5 i Spring Boot 2:

>> PROVJERITE TEČAJ

1. Pregled

U ovom ćemo se članku uglavnom usredotočiti na implementaciju paginacije na strani poslužitelja u a Proljetni REST API i jednostavan prednji kraj AngularJS.

Također ćemo istražiti često korištenu tabličnu mrežu u Angular pod nazivom UI Grid.

2. Ovisnosti

Ovdje detaljno opisujemo različite ovisnosti potrebne za ovaj članak.

2.1. JavaScript

Da bi Angular UI Grid mogao raditi, trebat će nam skripte u nastavku uvezene u naš HTML.

  • Kutni JS (1.5.8)
  • Kutna mreža sučelja

2.2. Maven

Za našu pozadinu koju ćemo koristiti Proljetni čizme, pa će nam trebati donje ovisnosti:

 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-tomcat 

Bilješka: Ostale ovisnosti ovdje nisu navedene, za potpuni popis provjerite cjelovitost pom.xml u projektu GitHub.

3. O aplikaciji

Aplikacija je jednostavna aplikacija direktorija učenika koja omogućava korisnicima da vide podatke o studentu u mrežici paginirane tablice.

Aplikacija koristi Proljetni čizme i izvodi se na ugrađenom Tomcat poslužitelju s ugrađenom bazom podataka.

Konačno, na strani API-ja postoji nekoliko načina za izvršavanje paginacije, opisanih u članku REST Paginacija u proljeće ovdje - što je preporučljivo pročitati zajedno s ovim člankom.

Naše je rješenje ovdje jednostavno - imati informacije o straničenju u URI upitu kako slijedi: / student / get? page = 1 & size = 2.

4. Na strani klijenta

Prvo, moramo stvoriti logiku na strani klijenta.

4.1. Mreža korisničkog sučelja

Naše index.html imat ćemo potreban uvoz i jednostavnu implementaciju tablične mreže:

Pogledajmo pobliže kôd:

  • ng-aplikacija - je kutna direktiva koja učitava modul app. Svi elementi ispod njih bit će dio app modul
  • ng-kontroler - je smjernica Angular koja učitava regulator StudentCtrl s aliasom od vm. Svi elementi ispod njih bit će dio StudentCtrl kontrolor
  • ui-mreža - je Angular direktiva koja pripada Angular-u ui-mreža i koristi gridOptions kao zadane postavke, gridOptions proglašava se pod $ opseg u app.js

4.2. Modul AngularJS

Prvo definirajmo modul u app.js:

var app = angular.module ('app', ['ui.grid', 'ui.grid.pagination']);

Proglasili smo app modul i ubrizgali smo ui.reška kako bi se omogućila funkcionalnost UI-Grid; također smo ubrizgavali ui.grid.paginacija kako bi se omogućila podrška za paginaciju.

Zatim ćemo definirati kontroler:

app.controller ('StudentCtrl', ['$ scope', 'StudentService', function ($ scope, StudentService) {var paginationOptions = {pageNumber: 1, pageSize: 5, sort: null}; StudentService.getStudents (paginationOptions.pageNumber , paginationOptions.pageSize) .success (funkcija (podaci) {$ scope.gridOptions.data = data.content; $ scope.gridOptions.totalItems = data.totalElements;}); $ scope.gridOptions = {paginationPageSizes: [5, 10 , 20], paginationPageSize: paginationOptions.pageSize, enableColumnMenus: false, useExternalPagination: true, columnDefs: [{name: 'id'}, {name: 'name'}, {name: 'gender'}, {name: 'age '}], onRegisterApi: funkcija (gridApi) {$ scope.gridApi = gridApi; gridApi.pagination.on.paginationChanged ($ opseg, funkcija (newPage, pageSize) {paginationOptions.pageNumber = newPage; paginationOptions.pageSize = pageSize; StudentService. getStudents (newPage, pageSize) .success (function (data) {$ scope.gridOptions.data = data.content; $ scope.gridOptions.totalItems = data.totalElements;}); }); }}; }]); 

Pogledajmo sada prilagođene postavke paginacije u $ scope.gridOptions:

  • paginationPageSizes - definira dostupne opcije veličine stranice
  • paginationPageSize - definira zadanu veličinu stranice
  • enableColumnMenus - koristi se za omogućavanje / onemogućavanje izbornika na stupcima
  • useExternalPagination - potrebno je ako paginirate na strani poslužitelja
  • columnDefs - imena stupaca koja će se automatski preslikati u JSON objekt vraćen s poslužitelja. Imena polja u JSON objektu vraćena s poslužitelja i definirani naziv stupca trebali bi se podudarati.
  • naRegisterApi - mogućnost registracije događaja javnih metoda unutar mreže. Ovdje smo registrirali gridApi.pagination.on.paginationChanged reći UI-Grid-u da aktivira ovu funkciju kad god je stranica promijenjena.

I za slanje zahtjeva API-ju:

app.service ('StudentService', ['$ http', function ($ http) {function getStudents (pageNumber, size) {pageNumber = pageNumber> 0? pageNumber - 1: 0; return $ http ({method: 'GET' , url: 'student / get? page =' + pageNumber + '& size =' + size});} return {getStudents: getStudents};}]);

5. Backend i API

5.1. RESTful usluga

Evo jednostavne implementacije RESTful API-ja s podrškom za paginaciju:

@RestController javna klasa StudentDirectoryRestController {@Autowired privatna usluga StudentService; @RequestMapping (value = "/ student / get", params = {"page", "size"}, method = RequestMethod.GET) javna stranica findPaginated (@RequestParam ("page") int page, @RequestParam ("size" ) int size) {Stranica resultPage = service.findPaginated (stranica, veličina); if (page> resultPage.getTotalPages ()) {throw new MyResourceNotFoundException (); } return resultPage; }}

The @RestController je predstavljen u proljeće 4.0 kao napomena o pogodnosti koja implicitno izjavljuje @Controller i @ResponseBody.

Za naš API proglasili smo da prihvaća dva parametra koja jesu stranica i veličina koja bi također odredila broj zapisa koje će se vratiti klijentu.

Također smo dodali jednostavnu provjeru valjanosti koja će baciti a MyResourceNotFoundException ako je broj stranice veći od ukupnog broja stranica.

Napokon ćemo se vratiti Stranica kao odgovor - ovo je super korisna komponenta S-apring Podaci koja ima podatke o paginaciji.

5.2. Provedba usluge

Naša usluga jednostavno će vratiti zapise na temelju stranice i veličine koje pruža kontrolor:

@Service javna klasa StudentServiceImpl implementira StudentService {@Autowired private StudentRepository dao; @Preuzmi javnu stranicu findPaginated (int stranica, int veličina) {return dao.findAll (novi PageRequest (stranica, veličina)); }} 

5.3. Implementacija spremišta

Za naš sloj postojanosti koristimo ugrađenu bazu podataka i Spring Data JPA.

Prvo, moramo postaviti našu trajnu konfiguraciju:

@EnableJpaRepositories ("com.baeldung.web.dao") @ComponentScan (basePackages = {"com.baeldung.web"}) @EntityScan ("com.baeldung.web.entity") @Configuration javna klasa PersistenceConfig {@Bean public JdbcTemplate getJdbcTemplate () {vratiti novi JdbcTemplate (dataSource ()); } @Bean public DataSource dataSource () {EmbeddedDatabaseBuilder builder = novi EmbeddedDatabaseBuilder (); EmbeddedDatabase db = builder .setType (EmbeddedDatabaseType.HSQL) .addScript ("db / sql / data.sql") .build (); povratak db; }} 

Konfiguracija postojanosti je jednostavna - imamo @EnableJpaRepositories za skeniranje navedenog paketa i pronalazak naših sučelja spremišta Spring Data JPA.

Mi imamo @ComponentScan ovdje da automatski pretražimo sav grah i mi imaju @EntityScan (iz Spring Boot) za skeniranje klasa entiteta.

Također smo proglasili naš jednostavan izvor podataka - koristeći ugrađenu bazu podataka koja će pokretati SQL skriptu koja se pruža prilikom pokretanja.

Sada je vrijeme da izradimo svoje spremište podataka:

javno sučelje StudentRepository proširuje JpaRepository {} 

To je u osnovi sve što ovdje moramo učiniti; ako želite dublje objasniti kako postaviti i koristiti vrlo snažni Spring Data JPA, svakako pročitajte ovdje vodič.

6. Paginacijski zahtjev i odgovor

Prilikom pozivanja API-ja - // localhost: 8080 / student / get? Page = 1 & size = 5, JSON odgovor izgledat će otprilike ovako:

{"content": [{"studentId": "1", "name": "Bryan", "gender": "Male", "age": 20}, {"studentId": "2", "name" : "Ben", "gender": "Male", "age": 22}, {"studentId": "3", "name": "Lisa", "gender": "Female", "age": 24 }, {"studentId": "4", "name": "Sarah", "gender": "Female", "age": 26}, {"studentId": "5", "name": "Jay" , "gender": "Male", "age": 20}], "last": false, "totalElements": 20, "totalPages": 4, "size": 5, "number": 0, "sort" : null, "first": true, "numberOfElements": 5} 

Ovdje treba primijetiti da poslužitelj vraća datoteku org.springframework.data.domain.Page DTO, omatanje našeg Student Resursi.

The Stranica objekt će imati sljedeća polja:

  • posljednji - postavljen pravi ako je posljednja stranica inače lažna
  • prvi - postavljen pravi ako je prva stranica inače lažna
  • totalElements - ukupan broj redaka / zapisa. U našem primjeru proslijedili smo ovo ui-mreža mogućnosti $ scope.gridOptions.totalItems kako bi se utvrdilo koliko će stranica biti dostupno
  • totalPages - ukupan broj stranica izveden iz (totalElements / size)
  • veličina - broj zapisa po stranici, koji je klijent proslijedio param veličina
  • broj - broj stranice koji je poslao klijent, u našem odgovoru broj je 0, jer u našoj pozadini koristimo niz od Students što je indeks zasnovan na nuli, pa u našem pozadinskom okruženju smanjujemo broj stranice za 1
  • vrsta - parametar sortiranja za stranicu
  • numberOfElements - broj redova / zapisa koji se vraćaju za stranicu

7. Testiranje paginacije

Postavimo sada test za našu logiku paginacije, koristeći RestAssured; da biste saznali više o Budite uvjereni možete pogledati ovaj vodič.

7.1. Priprema testa

Radi lakšeg razvoja naše testne klase dodavat ćemo statički uvoz:

io.restassured.RestAssured. * io.restassured.matcher.RestAssuredMatchers. * org.hamcrest.Matchers. *

Zatim ćemo postaviti test s proljetnim osposobljavanjem:

@RunWith (SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration (classes = Application.class) @WebAppConfiguration @IntegrationTest ("server.port: 8888") 

The @SpringApplicationConfiguration pomaže Spring da zna kako učitati ApplicationContext, u ovom smo slučaju koristili Primjena.java za konfiguriranje našeg ApplicationContext.

The @WebAppConfiguration bio je definiran da proljeću kaže da ApplicationContext biti učitan treba biti a WebApplicationContext.

I @IntegrationTest je definiran za pokretanje pokretanja aplikacije prilikom izvođenja testa, što čini naše REST usluge dostupnim za testiranje.

7.2. Ispitivanja

Evo našeg prvog test slučaja:

@Test javna praznina givenRequestForStudents_whenPageIsOne_expectContainsNames () {given (). Params ("page", "0", "size", "2"). Get (ENDPOINT). Then () .assertThat (). Body ("content.name ", hasItems (" Bryan "," Ben ")); } 

Ovaj gornji testni slučaj želi testirati da kada se stranica 1 i veličina 2 proslijede usluzi REST, JSON sadržaj vraćen s poslužitelja trebao bi imati imena Bryan i Ben.

Razdvojimo test slučaja:

  • dato - dio Budite uvjereni i koristi se za početak izrade zahtjeva, također možete koristiti s()
  • dobiti - dio Budite uvjereni a ako upotreba pokreće zahtjev za dobivanjem, koristite post () za zahtjev za postom
  • hasItems - dio hamcrest-a koji provjerava podudaraju li se vrijednosti

Dodamo još nekoliko testnih slučajeva:

@Test javna praznina givenRequestForStudents_whenResourcesAreRetrievedPaged_thenExpect200 () {given (). Params ("page", "0", "size", "2"). Get (ENDPOINT). Then () .statusCode (200); }

Ovaj test tvrdi da kada se tačka stvarno zove primljen je odgovor u redu:

@Test javna praznina givenRequestForStudents_whenSizeIsTwo_expectNumberOfElementsTwo () {given (). Params ("page", "0", "size", "2"). Get (ENDPOINT). Then () .assertThat (). Body ("numberOfElements", jednakTo (2)); }

Ovaj test tvrdi da kada se traži veličina stranice dvije, veličina stranice koja se vraća je zapravo dvije:

@Test javna praznina givenResourcesExist_whenFirstPageIsRetrieved_thenPageContainsResources () {given (). Params ("page", "0", "size", "2"). Get (ENDPOINT). Then () .assertThat (). Body ("first", jednakTo (istina)); } 

Ovaj test tvrdi da je, kad se resursi pozovu prvi put, vrijednost imena prve stranice istinita.

U spremištu ima još mnogo testova, pa svakako pogledajte projekt GitHub.

8. Zaključak

Ovaj je članak ilustrirao kako implementirati mrežu tablice podataka pomoću UI-Grid u KutniJS i kako implementirati potrebnu paginaciju na strani poslužitelja.

Provedba ovih primjera i testova može se naći u projektu GitHub. Ovo je Maven projekt, pa bi ga trebalo biti lako uvesti i pokrenuti kakav jest.

Da biste pokrenuli projekt pokretanja Spring, to jednostavno možete učiniti mvn spring-boot: trčanje i pristupite mu lokalno na // localhost: 8080 /.

OSTALO dno

Upravo sam najavio novo Uči proljeće tečaj, usredotočen na osnove Spring 5 i Spring Boot 2:

>> PROVJERITE TEČAJ