SpringRESTおよびAngularJSテーブルを使用したページネーション
1. 概要
この記事では、主に Spring RESTAPIと単純なAngularJSフロントエンドでのサーバー側のページ付けの実装に焦点を当てます。
また、 UIGridという名前のAngularで一般的に使用されるテーブルグリッドについても説明します。
2. 依存関係
ここでは、この記事に必要なさまざまな依存関係について詳しく説明します。
2.1. JavaScript
Angular UIグリッドを機能させるには、HTMLにインポートされた以下のスクリプトが必要です。
2.2. Maven
バックエンドにはSpring Bootを使用するため、以下の依存関係が必要になります。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
注:他の依存関係はここでは指定されていません。完全なリストについては、GitHubプロジェクトの完全なpom.xmlを確認してください。
3. アプリケーションについて
このアプリケーションは、ユーザーがページ化されたテーブルグリッドで学生の詳細を表示できるようにするシンプルな学生のディレクトリアプリです。
アプリケーションはSpringBoot を使用し、組み込みデータベースを備えた組み込みTomcatサーバーで実行されます。
最後に、API側では、ページネーションを行う方法がいくつかあります。これは、RESTページネーションインスプリングの記事で説明されています。これはこの記事と併せて読むことを強くお勧めします。
ここでの解決策は単純です。次のように、URIクエリにページング情報を含めます。 / student / get?page = 1&size = 2 。
4. クライアント側
まず、クライアント側のロジックを作成する必要があります。
4.1. UIグリッド
index.html には、必要なインポートとテーブルグリッドの簡単な実装が含まれます。
<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
<link rel="stylesheet" href="https://cdn.rawgit.com/angular-ui/
bower-ui-grid/master/ui-grid.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/
1.5.6/angular.min.js"></script>
<script src="https://cdn.rawgit.com/angular-ui/bower-ui-grid/
master/ui-grid.min.js"></script>
<script src="view/app.js"></script>
</head>
<body>
<div ng-controller="StudentCtrl as vm">
<div ui-grid="gridOptions" class="grid" ui-grid-pagination>
</div>
</div>
</body>
</html>
コードを詳しく見てみましょう。
- ng-app –モジュールappをロードするAngularディレクティブです。 これらの下にあるすべての要素は、appモジュールの一部になります
- ng-controller –コントローラーStudentCtrlにエイリアスvmをロードするAngularディレクティブです。これらの下のすべての要素はStudentCtrlの一部になりますコントローラー
- ui-grid – Angular ui-grid に属し、デフォルト設定としてgridOptionsを使用するAngularディレクティブです。gridOptionsが宣言されていますapp.jsの$scopeの下
4.2. AngularJSモジュール
まず、app.jsでモジュールを定義しましょう。
var app = angular.module('app', ['ui.grid','ui.grid.pagination']);
app モジュールを宣言し、ui.gridを挿入してUI-Grid機能を有効にしました。 また、 ui.grid.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;
});
});
}
};
}]);
$scope.gridOptionsのカスタムページネーション設定を見てみましょう。
- paginationPageSizes –使用可能なページサイズオプションを定義します
- paginationPageSize –デフォルトのページサイズを定義します
- enableColumnMenus –列のメニューを有効/無効にするために使用されます
- useExternalPagination –サーバー側でページ付けを行う場合は必須です
- columnDefs –サーバーから返されたJSONオブジェクトに自動的にマップされる列名。 サーバーから返されたJSONオブジェクトのフィールド名と、定義された列名は一致している必要があります。
- onRegisterApi –グリッド内のパブリックメソッドイベントを登録する機能。 ここでは、 gridApi.pagination.on.paginationChanged を登録して、ページが変更されるたびにこの関数をトリガーするように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サービス
ページ付けをサポートする単純なRESTfulAPIの実装は次のとおりです。
@RestController
public class StudentDirectoryRestController {
@Autowired
private StudentService service;
@RequestMapping(
value = "/student/get",
params = { "page", "size" },
method = RequestMethod.GET
)
public Page<Student> findPaginated(
@RequestParam("page") int page, @RequestParam("size") int size) {
Page<Student> resultPage = service.findPaginated(page, size);
if (page > resultPage.getTotalPages()) {
throw new MyResourceNotFoundException();
}
return resultPage;
}
}
@RestController は、@Controllerおよび@ResponseBody。を暗黙的に宣言する便利なアノテーションとしてSpring4.0で導入されました。
APIの場合、 page と、クライアントに返すレコードの数も決定するサイズの2つのパラメーターを受け入れるように宣言しました。
また、ページ数が合計ページ数よりも多い場合にMyResourceNotFoundExceptionをスローする簡単な検証を追加しました。
最後に、ページを応答として返します。これは、ページ付けデータを保持しているS pringDataの非常に役立つコンポーネントです。
5.2. サービスの実装
私たちのサービスは、コントローラーによって提供されたページとサイズに基づいてレコードを返すだけです。
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentRepository dao;
@Override
public Page<Student> findPaginated(int page, int size) {
return dao.findAll(new PageRequest(page, size));
}
}
5.3. リポジトリの実装
永続層には、組み込みデータベースとSpringDataJPAを使用しています。
まず、永続性構成をセットアップする必要があります。
@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;
}
}
永続性の構成は単純です。指定されたパッケージをスキャンしてSpringDataJPAリポジトリーインターフェースを見つけるための@EnableJpaRepositoriesがあります。
ここには、すべてのBeanを自動的にスキャンする @ComponentScan があり、エンティティクラスをスキャンする@EntityScan (Spring Bootから)があります。
また、起動時に提供されるSQLスクリプトを実行する組み込みデータベースを使用して、単純なデータソースを宣言しました。
次に、データリポジトリを作成します。
public interface StudentRepository extends JpaRepository<Student, Long> {}
基本的に、ここで行う必要があるのはこれだけです。 非常に強力なSpringDataJPAのセットアップ方法と使用方法について詳しく知りたい場合は、間違いなくここのガイドをお読みください。
6. ページネーションのリクエストとレスポンス
APIを呼び出すとき – http:// localhost:8080 / student / get?page = 1&size = 5 、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
}
ここで注意すべきことの1つは、サーバーが org.springframework.data.domain.Page DTOを返し、Studentリソースをラップしていることです。
ページオブジェクトには、次のフィールドがあります。
- last –最後のページがfalseの場合は、trueに設定します
- first –最初のページの場合は true に設定し、それ以外の場合はfalseに設定します
- totalElements –行/レコードの総数。 この例では、これをui-gridオプション$scope.gridOptions.totalItems に渡して、使用可能なページ数を決定しました。
- totalPages –( totalElements / size )から派生したページの総数
- size –ページあたりのレコード数。これはクライアントからparam sizeを介して渡されました。
- number –クライアントから送信されたページ番号。バックエンドではゼロベースのインデックスである Student の配列を使用しているため、応答では番号は0です。バックエンドでは、ページ番号を1つ減らします
- sort –ページのソートパラメーター
- numberOfElements –ページに返される行/レコードの数
7. ページネーションのテスト
次に、 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 は、Springが ApplicationContext、をロードする方法を知るのに役立ちます。この場合、Application.javaを使用して
@WebAppConfiguration は、ロードされるApplicationContextがWebApplicationContext。であることをSpringに通知するために定義されました。
また、 @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コンテンツの名前がBryanとBen。であることをテストするためのものです。
テストケースを分析してみましょう。
- give – RestAssured の一部であり、リクエストの作成を開始するために使用されます。 with()を使用することもできます
- get – RestAssured の一部であり、使用するとgetリクエストがトリガーされる場合は、postリクエストにpost()を使用します
- hasItems –値が一致するかどうかをチェックする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));
}
このテストは、2のページサイズが要求されたときに返されるページサイズが実際には2であることを表明します。
@Test
public void givenResourcesExist_whenFirstPageIsRetrieved_thenPageContainsResources() {
given().params("page", "0", "size", "2").get(ENDPOINT)
.then()
.assertThat().body("first", equalTo(true));
}
このテストは、リソースが最初に呼び出されたときに、最初のページ名の値がtrueであることを表明します。
リポジトリにはさらに多くのテストがあるので、GitHubプロジェクトをぜひご覧ください。
8. 結論
この記事では、AngularJSでUI-Gridを使用してデータテーブルグリッドを実装する方法と、必要なサーバー側のページ付けを実装する方法について説明しました。
これらの例とテストの実装は、GitHubプロジェクトにあります。 これはMavenプロジェクトなので、そのままインポートして実行するのは簡単です。
Springブートプロジェクトを実行するには、 mvn spring-boot:run を実行し、 http:// localhost:8080/。でローカルにアクセスします。