JAVA-3523 Move spring-rest-angular module
This commit is contained in:
7
spring-web-modules/spring-rest-angular/README.md
Normal file
7
spring-web-modules/spring-rest-angular/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## Spring REST Angular
|
||||
|
||||
This module contains articles about REST APIs with Spring and Angular
|
||||
|
||||
### Relevant Articles:
|
||||
|
||||
- [Pagination with Spring REST and AngularJS table](https://www.baeldung.com/pagination-with-a-spring-rest-api-and-an-angularjs-table)
|
||||
80
spring-web-modules/spring-rest-angular/pom.xml
Normal file
80
spring-web-modules/spring-rest-angular/pom.xml
Normal file
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-rest-angular</artifactId>
|
||||
<version>1.0</version>
|
||||
<name>spring-rest-angular</name>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>spring-mock-mvc</artifactId>
|
||||
<version>${rest-assured.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>spring-rest-angular</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<configuration>
|
||||
<failOnMissingWebXml>false</failOnMissingWebXml>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<guava.version>19.0</guava.version>
|
||||
<start-class>com.baeldung.web.main.Application</start-class>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.web.dao;
|
||||
|
||||
import com.baeldung.web.entity.Student;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface StudentRepository extends JpaRepository<Student, Long>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.baeldung.web.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Student implements Serializable {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public Student() {
|
||||
}
|
||||
|
||||
public Student(long id, String name, String gender, Integer age) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.gender = gender;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
@Id
|
||||
private long id;
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
@Column(nullable = false)
|
||||
private String gender;
|
||||
@Column(nullable = false)
|
||||
private Integer age;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getGender() {
|
||||
return gender;
|
||||
}
|
||||
|
||||
public void setGender(String gender) {
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
public Integer getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(Integer age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.baeldung.web.exception;
|
||||
|
||||
public class MyResourceNotFoundException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 4088649120307193208L;
|
||||
|
||||
public MyResourceNotFoundException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public MyResourceNotFoundException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public MyResourceNotFoundException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public MyResourceNotFoundException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.baeldung.web.main;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.web.filter.ShallowEtagHeaderFilter;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableAutoConfiguration
|
||||
@Import(PersistenceConfig.class)
|
||||
public class Application implements WebMvcConfigurer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ShallowEtagHeaderFilter shallowEtagHeaderFilter() {
|
||||
return new ShallowEtagHeaderFilter();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.baeldung.web.main;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||
|
||||
@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).build();
|
||||
return db;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.baeldung.web.rest;
|
||||
|
||||
import com.baeldung.web.entity.Student;
|
||||
import com.baeldung.web.exception.MyResourceNotFoundException;
|
||||
import com.baeldung.web.service.StudentService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class StudentDirectoryRestController {
|
||||
|
||||
@Autowired
|
||||
private StudentService service;
|
||||
|
||||
@RequestMapping(value = "/student/get", params = { "page", "size" }, method = RequestMethod.GET, produces = "application/json")
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.web.service;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
public interface IOperations<T> {
|
||||
|
||||
public Page<T> findPaginated(final int page, final int size);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.baeldung.web.service;
|
||||
|
||||
import com.baeldung.web.entity.Student;
|
||||
|
||||
public interface StudentService extends IOperations<Student> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.web.service;
|
||||
|
||||
import com.baeldung.web.dao.StudentRepository;
|
||||
import com.baeldung.web.entity.Student;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class StudentServiceImpl implements StudentService {
|
||||
|
||||
@Autowired
|
||||
private StudentRepository dao;
|
||||
|
||||
@Override
|
||||
public Page<Student> findPaginated(int page, int size) {
|
||||
return dao.findAll(PageRequest.of(page, size));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
server.servlet.contextPath=/
|
||||
spring.h2.console.enabled=true
|
||||
logging.level.org.hibernate.SQL=info
|
||||
spring.jpa.generate-ddl=true
|
||||
spring.jpa.hibernate.ddl-auto=create
|
||||
@@ -0,0 +1,40 @@
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (1,'Bryan', 'Male',20);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (2, 'Ben', 'Male', 22);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (3,'Lisa', 'Female',24);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (4,'Sarah', 'Female',20);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (5,'Jay', 'Male',20);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (6,'John', 'Male',22);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (7,'Jordan', 'Male',24);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (8,'Rob', 'Male',26);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (9,'Will', 'Male',20);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (10,'Shawn', 'Male',22);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (11,'Taylor', 'Female',24);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (12,'Venus', 'Female',26);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (13,'Vince', 'Male',20);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (14,'Carol', 'Female',22);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (15,'Joana', 'Female',24);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (16,'Dion', 'Male',26);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (17,'Evans', 'Male',20);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (18,'Bart', 'Male',22);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (19,'Jenny', 'Female',24);
|
||||
INSERT INTO student (id,name,gender,age)
|
||||
VALUES (20,'Kristine', 'Female',26);
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
||||
version="2.5">
|
||||
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.html</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
||||
</web-app>
|
||||
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" ng-app="app">
|
||||
<head>
|
||||
<link rel="stylesheet"
|
||||
href="//cdn.rawgit.com/angular-ui/bower-ui-grid/master/ui-grid.min.css">
|
||||
<script
|
||||
src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
|
||||
<script
|
||||
src="//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>
|
||||
@@ -0,0 +1,56 @@
|
||||
var app = angular.module('app', ['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;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}]);
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
}]);
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.baeldung;
|
||||
|
||||
import com.baeldung.web.main.Application;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Application.class)
|
||||
public class SpringContextTest {
|
||||
|
||||
@Test
|
||||
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.baeldung.web.service;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.hamcrest.core.IsCollectionContaining.hasItems;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import com.baeldung.web.main.Application;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class StudentServiceIntegrationTest {
|
||||
|
||||
@LocalServerPort
|
||||
int port;
|
||||
|
||||
private static final String ENDPOINT = "http://localhost:%s/student/get";
|
||||
|
||||
@Test
|
||||
public void givenRequestForStudents_whenPageIsOne_expectContainsNames() {
|
||||
given().params("page", "0", "size", "2").get(String.format(ENDPOINT, port)).then().assertThat()
|
||||
.body("content.name", hasItems("Bryan", "Ben"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenRequestForStudents_whenSizeIsTwo_expectTwoItems() {
|
||||
given().params("page", "0", "size", "2").get(String.format(ENDPOINT, port)).then().assertThat().body("size", equalTo(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenRequestForStudents_whenSizeIsTwo_expectNumberOfElementsTwo() {
|
||||
given().params("page", "0", "size", "2").get(String.format(ENDPOINT, port)).then().assertThat().body("numberOfElements", equalTo(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenRequestForStudents_whenResourcesAreRetrievedPaged_thenExpect200() {
|
||||
given().params("page", "0", "size", "2").get(String.format(ENDPOINT, port)).then().statusCode(200);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenRequestForStudents_whenPageOfResourcesAreRetrievedOutOfBounds_thenExpect500() {
|
||||
given().params("page", "1000", "size", "2").get(String.format(ENDPOINT, port)).then().statusCode(500);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenRequestForStudents_whenPageNotValid_thenExpect500() {
|
||||
given().params("page", RandomStringUtils.randomNumeric(5), "size", "2").get(String.format(ENDPOINT, port)).then().statusCode(500);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenRequestForStudents_whenPageSizeIsFive_expectFiveItems() {
|
||||
given().params("page", "0", "size", "5").get(String.format(ENDPOINT, port)).then().body("content.size()", is(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenResourcesExist_whenFirstPageIsRetrieved_thenPageContainsResources() {
|
||||
given().params("page", "0", "size", "2").get(String.format(ENDPOINT, port)).then().assertThat().body("first", equalTo(true));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user