1. 개요
이 기사에서는 주로 Spring REST API 및 간단한 AngularJS 프런트 엔드 에서 서버 측 페이지 매김을 구현하는 데 중점을 둘 것 입니다.
또한 Angular에서 UI Grid 라는 이름으로 일반적으로 사용되는 테이블 그리드를 탐색합니다 .
2. 의존성
여기에서는이 기사에 필요한 다양한 의존성을 자세히 설명합니다.
2.1. 자바 스크립트
Angular UI Grid가 작동하려면 HTML로 가져온 아래 스크립트가 필요합니다.
2.2. 메이븐
백엔드의 경우 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>
참고 : 다른 의존성은 여기에 지정되지 않았습니다. 전체 List을 보려면 GitHub 프로젝트 에서 전체 pom.xml 을 확인하세요 .
3. 신청에 관하여
이 응용 프로그램은 사용자가 페이지가 매겨진 표 그리드에서 학생 세부 정보를 볼 수있는 간단한 학생용 디렉토리 앱입니다.
이 애플리케이션은 Spring Boot를 사용 하며 임베디드 데이터베이스가있는 임베디드 Tomcat 서버에서 실행됩니다.
마지막으로 API 측면에서 페이지 나누기를 수행하는 몇 가지 방법이 있습니다. 여기에있는 Spring 의 REST Pagination 기사에 설명되어 있습니다.이 기사와 함께 읽어 보는 것이 좋습니다.
여기서 우리의 솔루션은 간단합니다. / student / get? page = 1 & size = 2 와 같이 URI 쿼리에 페이징 정보를 포함합니다 .
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 지시문입니다 . 이 아래의 모든 요소는 앱 모듈의 일부가됩니다.
- ng-controller – vm 별칭을 사용 하여 컨트롤러 StudentCtrl 을로드하는 Angular 지시문입니다 . 이 아래의 모든 요소는 StudentCtrl 컨트롤러의 일부입니다.
- UI - 그리드 - 각도에 속하는 각도 지침입니다 UI 그리드 및 사용 gridOptions , 기본 설정으로 gridOptions이 아래에 선언 $ 범위 에서 app.js
4.2. AngularJS 모듈
먼저 app.js 에서 모듈을 정의 하겠습니다 .
var app = angular.module('app', ['ui.grid','ui.grid.pagination']);
앱 모듈을 선언하고 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 – 그리드 내부에 공개 메소드 이벤트를 등록하는 기능. 여기서 우리 는 페이지가 변경 될 때마다이 함수를 트리거하도록 UI-Grid에 알리기 위해 gridApi.pagination.on.paginationChanged 를 등록했습니다 .
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 서비스
다음은 페이지 매김을 지원하는 간단한 RESTful API 구현입니다.
@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는 암시 적 선언의 편의를 어노테이션으로 Spring 4.0에 도입 된 @Controller 와 @ResponseBody를.
API의 경우 클라이언트에 반환 할 레코드 수를 결정하는 페이지 와 크기 인 두 개의 매개 변수를 허용하도록 선언했습니다 .
또한 페이지 번호가 총 페이지 수보다 높으면 MyResourceNotFoundException을 발생 시키는 간단한 유효성 검사를 추가했습니다 .
마지막으로 페이지 를 응답으로 반환 합니다. 이것은 페이지 매김 데이터를 보유한 S pring 데이터 의 매우 유용한 구성 요소입니다 .
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. 리포지토리 구현
지속성 계층의 경우 임베디드 데이터베이스와 SpringData JPA를 사용하고 있습니다.
먼저 지속성 구성을 설정해야합니다.
@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;
}
}
지속성 구성은 간단합니다. @EnableJpaRepositories 를 사용하여 지정된 패키지를 스캔하고 SpringData JPA 저장소 인터페이스를 찾습니다.
여기에는 모든 빈을 자동으로 스캔 하는 @ComponentScan 이 있고 엔티티 클래스를 스캔하는 @EntityScan (Spring Boot)이 있습니다.
또한 시작시 제공되는 SQL 스크립트를 실행하는 내장 데이터베이스를 사용하여 간단한 데이터 소스를 선언했습니다.
이제 데이터 저장소를 만들 차례입니다.
public interface StudentRepository extends JpaRepository<Student, Long> {}
이것은 기본적으로 우리가 여기서해야 할 모든 것입니다. 매우 강력한 SpringData JPA를 설정하고 사용하는 방법에 대해 자세히 알아 보려면 여기에서 가이드를 읽어보십시오 .
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
}
여기서 주목해야 할 점은 서버가 학생 리소스를 래핑 하는 org.springframework.data.domain.Page DTO를 반환한다는 것 입니다.
페이지 객체에는 다음과 같은 필드가있을 것이다 :
- last – 마지막 페이지 이면 true로 설정하고 그렇지 않으면 false로 설정합니다.
- first – 첫 페이지 이면 true로 설정하고 그렇지 않으면 false
- totalElements – 총 행 / 레코드 수입니다. 이 예에서는이를 ui-grid 옵션 $ scope.gridOptions.totalItems에 전달 하여 사용할 수있는 페이지 수를 결정했습니다.
- totalPages – ( totalElements / size ) 에서 파생 된 총 페이지 수
- size – 페이지 당 레코드 수, 매개 변수 크기 를 통해 클라이언트에서 전달됨
- number – 클라이언트가 보낸 페이지 번호, 응답에서 숫자는 0입니다. 백엔드 에서는 0부터 시작하는 인덱스 인 Student 배열을 사용하고 있으므로 백엔드에서는 페이지 번호를 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를 우리의 구성 의 ApplicationContext를.
@WebAppConfiguration는 것을 Spring에게 정의 의 ApplicationContext가 해야한다로드 할 수 의 WebApplicationContext.
그리고 @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 이어야하는지 테스트하기위한 것 입니다.
테스트 케이스를 분석해 보겠습니다.
- given – RestAssured 의 일부이며 요청 빌드를 시작하는 데 사용됩니다. with ()를 사용할 수도 있습니다.
- get – RestAssured 의 일부이며 사용되는 경우 get 요청을 트리거하면 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));
}
이 테스트는 리소스가 처음 호출 될 때 첫 번째 페이지 이름 값이 참임을 확인합니다.
저장소에는 더 많은 테스트가 있으므로 반드시 GitHub 프로젝트를 살펴보십시오 .
8. 결론
이 기사에서는 AngularJS 에서 UI-Grid 를 사용하여 데이터 테이블 그리드 를 구현하는 방법과 필요한 서버 측 페이지 매김을 구현하는 방법을 설명했습니다.
이러한 예제 및 테스트의 구현은 GitHub 프로젝트 에서 찾을 수 있습니다 . 이것은 Maven 프로젝트이므로 그대로 가져 와서 실행하기 쉽습니다.
Spring 부트 프로젝트를 실행하려면 mvn spring-boot : run을 수행 하고 http : // localhost : 8080 / 에서 로컬로 액세스하면됩니다 .
- https://docs.spring.io/spring-framework/docs/current/reference/html
- https://www.baeldung.com/pagination-with-a-spring-rest-api-and-an-angularjs-table
'Java' 카테고리의 다른 글
Apache Meecrowave로 마이크로 서비스 구축 (0) | 2021.03.15 |
---|---|
스프링 테스트의 WebAppConfiguration (0) | 2021.03.15 |
Spring REST API에 대한 요청 제한 시간 설정 (0) | 2021.03.14 |
코어 자바의 동작 패턴 (0) | 2021.03.14 |
Spring 이메일 연동방법 (0) | 2021.03.13 |