Paginacija s Spring REST i AngularJS tablicom
Upravo sam najavio novo Uči proljeće tečaj, usredotočen na osnove Spring 5 i Spring Boot 2:
>> PROVJERITE TEČAJ1. 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