AngularJS CRUD Application with Spring Data REST – 使用Spring Data REST的AngularJS CRUD应用程序

最后修改: 2017年 3月 6日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’re going to create an example of a simple CRUD application using AngularJS for the front-end and Spring Data REST for the back-end.

在本教程中,我们将创建一个简单的CRUD应用实例,前端使用AngularJS,后端使用Spring Data REST。

2. Creating the REST Data Service

2.创建REST数据服务

In order to create the support for persistence, we’ll make use of the Spring Data REST specification that will enable us to perform CRUD operations on a data model.

为了创建对持久性的支持,我们将利用Spring Data REST规范,这将使我们能够对数据模型进行CRUD操作。

You can find all the necessary information on how to setup the REST endpoints in the introduction to Spring Data REST. In this article, we will reuse the existing project we have setup for the introduction tutorial.

您可以在Spring Data REST 介绍中找到有关如何设置 REST 端点的所有必要信息。在本文中,我们将重新使用我们在介绍教程中设置的现有项目。

For persistence, we will use the H2 in memory database.

对于持久性,我们将使用H2内存数据库。

As a data model, the previous article defines a WebsiteUser class, with id, name and email properties and a repository interface called UserRepository.

作为一个数据模型,前面的文章定义了一个WebsiteUser类,有idnameemail属性和一个名为UserRepository的存储库接口。

Defining this interface instructs Spring to create the support for exposing REST collection resources and item resources. Let’s take a closer look at the endpoints available to us now that we will later call from AngularJS.

定义这个接口指示Spring创建对暴露REST集合资源和项目资源的支持。让我们仔细看看现在可用的端点,我们以后将从AngularJS中调用。

2.1. The Collection Resources

2.1.收集资源

A list of all the users will be available to us at the endpoint /users. This URL can be called using the GET method and will return JSON objects of the form:

所有用户的列表将在端点/users上提供给我们。这个URL可以用GET方法调用,并将返回JSON格式的对象。

{
  "_embedded" : {
    "users" : [ {
      "name" : "Bryan",
      "age" : 20,
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/users/1"
        },
        "User" : {
          "href" : "http://localhost:8080/users/1"
        }
      }
    }, 
...
    ]
  }
}

2.2. The Item Resources

2.2.项目资源

A single WebsiteUser object can be manipulated by accessing URLs of the form /users/{userID} with different HTTP methods and request payloads.

一个单一的WebsiteUser对象可以通过访问/users/{userID}形式的URL,用不同的HTTP方法和请求有效载荷进行操作。

For retrieving a WebsiteUser object, we can access /users/{userID} with the GET method. This returns a JSON object of the form:

为了检索WebsiteUser对象,我们可以用GET方法访问/users/{userID}。这将返回一个JSON格式的对象。

{
  "name" : "Bryan",
  "email" : "bryan@yahoo.com",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/users/1"
    },
    "User" : {
      "href" : "http://localhost:8080/users/1"
    }
  }
}

To add a new WebsiteUser, we will need to call /users with POST method. The attributes of the new WebsiteUser record will be added in the request body as a JSON object:

要添加一个新的WebsiteUser,我们需要用POST方法调用/users。新WebsiteUser记录的属性将以JSON对象的形式添加到请求体中。

{name: "Bryan", email: "bryan@yahoo.com"}

If there are no errors, this URL returns a status code 201 CREATED.

如果没有错误,这个URL返回状态代码201 CREATED。

If we want to update the attributes of the WebsiteUser record, we need to call the URL /users/{UserID} with the PATCH method and a request body containing the new values:

如果我们想更新WebsiteUser记录的属性,我们需要用PATCH方法调用URL /users/{UserID},并提供包含新值的请求体。

{name: "Bryan", email: "bryan@gmail.com"}

To delete a WebsiteUser record, we can call the URL /users/{UserID} with the DELETE method. If there are no errors, this returns status code 204 NO CONTENT.

要删除一条WebsiteUser记录,我们可以用DELETE方法调用URL /users/{UserID}。如果没有错误,这将返回状态代码204 NO CONTENT。

2.3. MVC Configuration

2.3.MVC配置

We’ll also add a basic MVC configuration to display html files in our application:

我们还将添加一个基本的MVC配置,在我们的应用程序中显示html文件。

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
    
    public MvcConfig(){
        super();
    }
    
    @Override
    public void configureDefaultServletHandling(
      DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

   @Bean
   WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> enableDefaultServlet() {
     return (factory) -> factory.setRegisterDefaultServlet(true);
   }
}

2.4. Allowing Cross Origin Requests

2.4.允许跨源请求

If we want to deploy the AngularJS front-end application separately than the REST API – then we need to enable cross-origin requests.

如果我们想将AngularJS前端应用程序与REST API分开部署–那么我们需要启用跨源请求。

Spring Data REST has added support for this starting with version 1.5.0.RELEASE. To allow requests from a different domain, all you have to do is add the @CrossOrigin annotation to the repository:

从1.5.0.RELEASE版本开始,Spring Data REST已经添加了这方面的支持。要允许来自不同领域的请求,你所要做的就是将@CrossOrigin注解添加到资源库中。

@CrossOrigin
@RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserRepository extends CrudRepository<WebsiteUser, Long> {}

As a result, on every response from the REST endpoints, a header of Access-Control-Allow-Origin will be added.

因此,在REST端点的每个响应中,将添加一个Access-Control-Allow-Origin的头。

3. Creating the AngularJS Client

3.创建AngularJS客户端

For creating the front end of our CRUD application, we’ll use AngularJS – a well-know JavaScript framework that eases the creation of front-end applications.

为了创建我们的CRUD应用程序的前端,我们将使用AngularJS–一个众所周知的JavaScript框架,它简化了前端应用程序的创建。

In order to use AngularJS, we first need to include the angular.min.js file in our html page that will be called users.html:

为了使用AngularJS,我们首先需要在我们的html页面中包含angular.min.js文件,该页面将被称为users.html

<script 
  src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js">
</script>

Next, we need to create an Angular module, controller, and service that will call the REST endpoints and display the returned data.

接下来,我们需要创建一个Angular模块、控制器和服务,来调用REST端点并显示返回的数据。

These will be placed in a JavaScript file called app.js that also needs to be included in the users.html page:

这些将被放置在一个名为 app.js的JavaScript文件中,该文件也需要被包含在 users.html页面中。

<script src="view/app.js"></script>

3.1. Angular Service

3.1.Angular服务

First, let’s create an Angular service called UserCRUDService that will make use of the injected AngularJS $http service to make calls to the server. Each call will be placed in a separate method.

首先,让我们创建一个名为UserCRUDService的Angular服务,它将利用注入的AngularJS $http服务来对服务器进行调用。每个调用将被放在一个单独的方法中。

Let’s take a look at defining the method for retrieving a user by id using the /users/{userID} endpoint:

让我们看看如何定义使用/users/{userID}端点按id检索用户的方法。

app.service('UserCRUDService', [ '$http', function($http) {

    this.getUser = function getUser(userId) {
        return $http({
            method : 'GET',
            url : 'users/' + userId
        });
    }
} ]);

Next, let’s define the addUser method which makes a POST request to the /users URL and sends the user values in the data attribute:

接下来,让我们定义addUser方法,向/users URL发出POST请求,并在data属性中发送用户值。

this.addUser = function addUser(name, email) {
    return $http({
        method : 'POST',
        url : 'users',
        data : {
            name : name,
            email: email
        }
    });
}

The updateUser method is similar to the one above, except it will have an id parameter and makes a PATCH request:

updateUser方法与上述方法类似,只是它将有一个id参数,并提出一个PATCH请求。

this.updateUser = function updateUser(id, name, email) {
    return $http({
        method : 'PATCH',
        url : 'users/' + id,
        data : {
            name : name,
            email: email
        }
    });
}

The method for deleting a WebsiteUser record will make a DELETE request:

删除WebsiteUser记录的方法将发出一个DELETE请求。

this.deleteUser = function deleteUser(id) {
    return $http({
        method : 'DELETE',
        url : 'users/' + id
    })
}

And finally, let’s take a look at the methods for retrieving the entire list of users:

最后,让我们看一下检索整个用户列表的方法。

this.getAllUsers = function getAllUsers() {
    return $http({
        method : 'GET',
        url : 'users'
    });
}

All of these service methods will be called by an AngularJS controller.

所有这些服务方法将由AngularJS控制器调用。

3.2. Angular Controller

3.2.Angular控制器

We will create an UserCRUDCtrl AngularJS controller that will have an UserCRUDService injected and will use the service methods to obtain the response from the server, handle the success and error cases, and set $scope variables containing the response data for displaying it in the HTML page.

我们将创建一个UserCRUDCtrlAngularJS控制器,该控制器将注入UserCRUDService,并使用该服务方法从服务器获取响应,处理successerror情况,并设置$scope变量,该变量包含响应数据以在HTML页面上显示。

Let’s take a look at the getUser() function that calls the getUser(userId) service function and defines two callback methods in case of success and error. If the server request succeeds, then the response is saved in a user variable; otherwise, error messages are handled:

让我们看看getUser()函数,它调用getUser(userId)服务函数,并定义了成功和错误时的两个回调方法。如果服务器请求成功,那么响应被保存在user变量中;否则,错误信息将被处理。

app.controller('UserCRUDCtrl', ['$scope','UserCRUDService', 
  function ($scope,UserCRUDService) {
      $scope.getUser = function () {
          var id = $scope.user.id;
          UserCRUDService.getUser($scope.user.id)
            .then(function success(response) {
                $scope.user = response.data;
                $scope.user.id = id;
                $scope.message='';
                $scope.errorMessage = '';
            },
    	    function error (response) {
                $scope.message = '';
                if (response.status === 404){
                    $scope.errorMessage = 'User not found!';
                }
                else {
                    $scope.errorMessage = "Error getting user!";
                }
            });
      };
}]);

The addUser() function will call the corresponding service function and handle the response:

addUser()函数将调用相应的服务函数并处理响应。

$scope.addUser = function () {
    if ($scope.user != null && $scope.user.name) {
        UserCRUDService.addUser($scope.user.name, $scope.user.email)
          .then (function success(response){
              $scope.message = 'User added!';
              $scope.errorMessage = '';
          },
          function error(response){
              $scope.errorMessage = 'Error adding user!';
              $scope.message = '';
        });
    }
    else {
        $scope.errorMessage = 'Please enter a name!';
        $scope.message = '';
    }
}

The updateUser() and deleteUser() functions are similar to the one above:

updateUser()deleteUser()函数与上述函数类似。

$scope.updateUser = function () {
    UserCRUDService.updateUser($scope.user.id, 
      $scope.user.name, $scope.user.email)
      .then(function success(response) {
          $scope.message = 'User data updated!';
          $scope.errorMessage = '';
      },
      function error(response) {
          $scope.errorMessage = 'Error updating user!';
          $scope.message = '';
      });
}

$scope.deleteUser = function () {
    UserCRUDService.deleteUser($scope.user.id)
      .then (function success(response) {
          $scope.message = 'User deleted!';
          $scope.User = null;
          $scope.errorMessage='';
      },
      function error(response) {
          $scope.errorMessage = 'Error deleting user!';
          $scope.message='';
      });
}

And finally, let’s define the function that retrieves a list of users, and stores it in the users variable:

最后,让我们定义一个检索用户列表的函数,并将其存储在users变量中。

$scope.getAllUsers = function () {
    UserCRUDService.getAllUsers()
      .then(function success(response) {
          $scope.users = response.data._embedded.users;
          $scope.message='';
          $scope.errorMessage = '';
      },
      function error (response) {
          $scope.message='';
          $scope.errorMessage = 'Error getting users!';
      });
}

3.3. HTML Page

3.3.HTML页面

The users.html page will make use of the controller functions defined in the previous section and the stored variables.

users.html页面将利用上一节中定义的控制器函数和存储的变量。

First, in order to use the Angular module, we need to set the ng-app property:

首先,为了使用Angular模块,我们需要设置 ng-app属性。

<html ng-app="app">

Then, to avoid typing UserCRUDCtrl.getUser() every time we use a function of the controller, we can wrap our HTML elements in a div with a ng-controller property set:

然后,为了避免每次使用控制器的函数时都要输入UserCRUDCtrl.getUser(),我们可以用div包装我们的HTML元素,并设置ng-controller属性。

<div ng-controller="UserCRUDCtrl">

Let’s create the form that will input and display the values for the WebiteUser object we want to manipulate. Each of these will have a ng-model attribute set, which binds it to the value of the attribute:

让我们创建表单,它将输入并显示我们要操作的WebiteUser对象的值。每一个都将有一个ng-model属性设置,将其与属性的值绑定。

<table>
    <tr>
        <td width="100">ID:</td>
        <td><input type="text" id="id" ng-model="user.id" /></td>
    </tr>
    <tr>
        <td width="100">Name:</td>
        <td><input type="text" id="name" ng-model="user.name" /></td>
    </tr>
    <tr>
        <td width="100">Age:</td>
        <td><input type="text" id="age" ng-model="user.email" /></td>
    </tr>
</table>

Binding the id input to the user.id variable, for example, means that whenever the value of the input is changed, this value is set in the user.id variable and vice versa.

例如,将id输入与user.id变量绑定,意味着每当输入的值被改变,这个值就会被设置在user.id变量中,反之亦然。

Next, let’s use the ng-click attribute to define the links that will trigger the invoking of each CRUD controller function defined:

接下来,让我们使用ng-click属性来定义链接,这些链接将触发每个定义的CRUD控制器功能的调用。

<a ng-click="getUser(user.id)">Get User</a>
<a ng-click="updateUser(user.id,user.name,user.email)">Update User</a>
<a ng-click="addUser(user.name,user.email)">Add User</a>
<a ng-click="deleteUser(user.id)">Delete User</a>

Finally, let’s display the list of users entirely and by name:

最后,让我们完全按照名字来显示用户的列表。

<a ng-click="getAllUsers()">Get all Users</a><br/><br/>
<div ng-repeat="usr in users">
{{usr.name}} {{usr.email}}

4. Conclusion

4.结论

In this tutorial, we have shown how you can create a CRUD application using AngularJS and the Spring Data REST specification.

在本教程中,我们展示了如何使用AngularJSSpring Data REST规范创建一个CRUD应用程序。

The complete code for the above example can be found in the GitHub project.

上述例子的完整代码可以在GitHub项目中找到。

To run the application, you can use the command mvn spring-boot:run and access the URL /users.html.

要运行应用程序,你可以使用mvn spring-boot:run命令并访问URL /users.html