Рубрики
Без рубрики

Пагинация с весенним REST и таблицей AngularJS

Обширный взгляд на то, как реализовать простой API с pagination с spring и как потреблять его с AngularJS и UI Grid.

Автор оригинала: baeldung.

Пагинация с весенним REST и таблицей AngularJS

1. Обзор

В этой статье мы сосредоточимся в основном на реализации pagination стороны сервера в Весенний REST API и простой передний конец AngularJS.

Мы также исследуем широко используемую сетку таблицы в Angular под названием UI Grid .

2. Зависимости

Здесь мы подробно различные зависимости, которые необходимы для этой статьи.

2.1. JavaScript

Для того, чтобы Angular UI Grid работал, нам понадобится ниже скрипты, импортированные в нашем HTML.

2.2. Мавен

Для нашего бэкэнда мы будем использовать Весенняя загрузка , так что нам понадобится ниже зависимостей:


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


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

Примечание: Другие зависимости не были указаны здесь, для полного списка, проверьте полный пом.xml в GitHub проект.

3. О заявке

Приложение является простым студенческим каталогом приложение, которое позволяет пользователям видеть детали студента в paginated таблице сетки.

Приложение использует Весенняя загрузка и работает на встроенном сервере Tomcat со встроенной базой данных.

Наконец, на стороне API вещей, Есть несколько способов сделать pagination, описанные в REST Pagination весной статьи здесь – что настоятельно рекомендуется чтение в сочетании с этой статьей.

Наше решение здесь простое – иметь информацию о paging в запросе URI следующим образом: /студент/получить?page-размер 2 .

4. Клиентская сторона

Во-первых, нам нужно создать логику на стороне клиента.

4.1. UI-Grid

Наша индекс.html будет иметь импорт нам нужно и простое осуществление таблицы сетки:




    
        
        
        
        
    
    
        

Давайте более подробно рассмотрим код:

  • ng-app – это угловая директива, которая загружает модуль приложение . Все элементы под ним будут частью приложение модуль
  • ng-контроллер – это угловая директива, которая загружает контроллер СтуденческаяКтрл с псевдонимом vm. Все элементы под ним будут частью СтуденческаяКтрл контроллер
  • ui-сетка – это угловая директива, которая принадлежит Angular ui-сетка и использует gridOptions в качестве настроек по умолчанию, gridOptions объявляется в соответствии с $scope в приложение.js

4.2. Модуль AngularJS

Давайте сначала определим модуль в приложение.js :

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

Мы объявили приложение модуль, и мы ввели ui.grid для включения функциональности UI-Grid; мы также вводили ui.grid.pagination для поддержки pagination.

Далее мы определим контроллер:

app.controller('StudentCtrl', ['$scope','StudentService', 
    function ($scope, StudentService) {
        var paginationOptions = {
            pageNumber: 1,
            pageSize: 5,
        sort: null
        };

    StudentService.getStudents(
      paginationOptions.pageNumber,
      paginationOptions.pageSize).success(function(data){
        $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: function(gridApi) {
           $scope.gridApi = gridApi;
           gridApi.pagination.on.paginationChanged(
             $scope, 
             function (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;
                 });
            });
        }
    };
}]);

Давайте теперь посмотрим на пользовательские настройки pagination в $scope.gridOptions :

  • paginationPageSizes – определяет доступные параметры размера страницы
  • paginationPageSize – определяет размер страницы по умолчанию
  • включитьКолумнМенус – используется для включения/отключения меню в столбцах
  • использованиеИстерналПагинация – требуется, если вы paginating на стороне сервера
  • колонкаДефы — имена столбца, которые будут автоматически отображены на объект JSON, возвращенный с сервера. Имена поля в объекте JSON, возвращенные с сервера, и определенное имя столбца должны соответствовать.
  • onRegisterApi – возможность регистрации публичных методов событий внутри сетки. Здесь мы зарегистрировали gridApi.pagination.on.paginationИзмеленные чтобы сообщить UI-Grid, чтобы вызвать эту функцию всякий раз, когда страница была изменена.

И отправить запрос в API:

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. Бэкэнд и API

5.1. Служба RESTful

Вот простая реализация API RESTful с поддержкой pagination:

@RestController
public class StudentDirectoryRestController {

    @Autowired
    private StudentService service;

    @RequestMapping(
      value = "/student/get", 
      params = { "page", "size" }, 
      method = RequestMethod.GET
    )
    public Page findPaginated(
      @RequestParam("page") int page, @RequestParam("size") int size) {

        Page resultPage = service.findPaginated(page, size);
        if (page > resultPage.getTotalPages()) {
            throw new MyResourceNotFoundException();
        }

        return resultPage;
    }
}

@RestController была введена весной 4.0 как удобная аннотация, которая неявно @Controller и @ResponseBody.

Для нашего API, мы объявили его принять два параметра, которые страница и размер, который также будет определять количество записей, чтобы вернуться к клиенту.

Мы также добавили простую проверку, которая бросит MyResourceNotFoundException если число страниц превышает общее количество страниц.

Наконец, мы вернемся Страница как ответ – это супер полезный компонент S pring Данные который провел pagination данных.

5.2. Внедрение службы

Наш сервис просто вернет записи на основе страницы и размера, предоставленных контроллером:

@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentRepository dao;

    @Override
    public Page findPaginated(int page, int size) {
        return dao.findAll(new PageRequest(page, size));
    }
}

5.3. Реализация репозитория

Для нашего уровня настойчивости мы используем встроенную базу данных и Spring Data JPA.

Во-первых, мы должны настроить нашу настойчивость config:

@EnableJpaRepositories("com.baeldung.web.dao")
@ComponentScan(basePackages = { "com.baeldung.web" })
@EntityScan("com.baeldung.web.entity") 
@Configuration
public class PersistenceConfig {

    @Bean
    public JdbcTemplate getJdbcTemplate() {
        return new JdbcTemplate(dataSource());
    }

    @Bean
    public DataSource dataSource() {
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        EmbeddedDatabase db = builder
          .setType(EmbeddedDatabaseType.HSQL)
          .addScript("db/sql/data.sql")
          .build();
        return db;
    }
}

Настойчивость config проста – у нас есть @EnableJpaRepositories сканировать указанный пакет и найти наши интерфейсы репозитория Spring Data JPA.

У нас есть @ComponentScan здесь, чтобы автоматически сканировать для всех бобов, и мы есть @EntityScan (от Spring Boot) для сканирования классов сущностей.

Мы также объявили наш простой источник данных – с помощью встроенной базы данных, которая будет работать скрипт S’L, предусмотренный при запуске.

Теперь пришло время создать наш репозиторий данных:

public interface StudentRepository extends JpaRepository {}

Это в основном все, что нам нужно сделать здесь; если вы хотите пойти глубже в том, как настроить и использовать очень мощный Весенние данные JPA, безусловно, читать руководство к нему здесь .

6. Запрос и ответ на вопросы о палации

При вызове API , JSON ответ будет выглядеть что-то вроде этого:

{
    "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
}

Одна вещь, чтобы заметить здесь, что сервер возвращает org.springframework.data.domain.Page DTO, упаковка наших Студенческие ресурсы.

Страница объект будет иметь следующие поля:

  • последний – установлен на истинное если это последняя страница в противном случае ложные
  • первый – установлен на истинное если это первая страница в противном случае ложные
  • totalElements – общее количество строк/записей. В нашем примере мы передали это ui-сетка варианты $scope.gridOptions.totalItems определить, сколько страниц будет доступно
  • totalPages – общее количество страниц, которые были получены из ( totalElements/размер )
  • размер – количество записей на страницу, это было передано от клиента через param размер
  • номер – номер страницы, отправленный клиентом, в нашем ответе номер 0, потому что в нашем бэкэнде мы используем массив Студенческие s, который является нулевым индексом, так что в нашем бэкэнде, мы decrement номер страницы на 1
  • сортировать – параметр сортировки страницы
  • numberOfElements – количество строк/записей для страницы

7. Тестирование pagination

Теперь давайте навеем тест на нашу логику pagination, используя RestAssured ; чтобы узнать больше о RestAssured Вы можете взглянуть на эту учебный .

7.1. Подготовка теста

Для удобства развития нашего тестового класса мы добавим статический импорт:

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

Далее мы наберем тест с поддержкой Spring:

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

@SpringApplicationConfiguration помогает Весна знать, как загрузить ПриложениеКонтекст, в этом случае мы использовали Применение.java настроить наши ПриложениеКонтекст.

@WebAppConfiguration был определен, чтобы сказать Весна, что ПриложениеКонтекст загрузка должна быть WebApplicationКонтекст.

И @IntegrationTest был определен, чтобы вызвать запуск приложения при запуске теста, это делает наши услуги REST доступными для тестирования.

7.2. Тесты

Вот наш первый тестовый случай:

@Test
public void givenRequestForStudents_whenPageIsOne_expectContainsNames() {
    given().params("page", "0", "size", "2").get(ENDPOINT)
      .then()
      .assertThat().body("content.name", hasItems("Bryan", "Ben"));
}

Этот тестовый случай выше, чтобы проверить, что при странице 1 и размер 2 передается в службу REST JSON содержание возвращается с сервера должны иметь имена Брайан и Бен.

Давайте вскроем тестовый случай:

  • учитывая – часть RestAssured и используется для начала построения запроса, вы также можете использовать с ()
  • получить – часть RestAssured и если используется триггеры получить запрос, используйте пост () для запроса на почту
  • имеетItems – часть hamcrest, который проверяет, если значения имеют какой-либо матч

Добавим еще несколько тестовых случаев:

@Test
public void givenRequestForStudents_whenResourcesAreRetrievedPaged_thenExpect200() {
    given().params("page", "0", "size", "2").get(ENDPOINT)
      .then()
      .statusCode(200);
}

Этот тест утверждает, что, когда точка на самом деле называется OK ответ получен:

@Test
public void givenRequestForStudents_whenSizeIsTwo_expectNumberOfElementsTwo() {
    given().params("page", "0", "size", "2").get(ENDPOINT)
      .then()
      .assertThat().body("numberOfElements", equalTo(2));
}

Этот тест утверждает, что при запрашиваемом размере страницы в два страницы размер возвращен на самом деле составляет два:

@Test
public void givenResourcesExist_whenFirstPageIsRetrieved_thenPageContainsResources() {
    given().params("page", "0", "size", "2").get(ENDPOINT)
      .then()
      .assertThat().body("first", equalTo(true));
}

Этот тест утверждает, что при первом использовании ресурсов значение имени первой страницы верно.

Есть еще много тестов в репозитории, так что определенно посмотрите на GitHub проект.

8. Заключение

Эта статья проиллюстрировала, как реализовать сетку таблиц данных с помощью UI-Grid в AngularJS и как реализовать требуемую pagination стороны сервера.

Реализация этих примеров и тестов можно найти в Проект GitHub . Это проект Maven, поэтому он должен быть легким для импорта и запуска, как она есть.

Чтобы запустить проект загрузки Spring, вы можете просто сделать mvn весна-загрузка:бегите и получить доступ к нему локально http://localhost:8080/.