Das Beispiel: CRUD mit Spring Boot, REST und AngularJS

View more categories:

1- Das Zweck des Artikel

Im Artikel werde ich Sie bei der Erstellung einer einfachen Applikation anleiten, die die Technologies  Spring Boot, Rest und  AngularJS kombiniert. Zuerst können Sie die Applikation vorschauen, die wir implementieren werden:
AngularJS ist eine Open-Source-Code Bibliothek und basiert auf  Javascript, und hilft Ihnen bei der Aufbau der Applikation  Single Page . In der Unterricht werde ich eine Seite erstellen und die Seite zeigt die Liste von Mitarbeiter an, gleichzeitig erlaubt Sie, die Mitarbeiter einzufügen, zu löschen und bearbeiten.
Die Fragen werden in diese Unterricht erwähnt werden:
  1. Eine ApplikationSpring Boot erstellen.
  2. Die REST API mit der Funktionen erstellen: die Daten abfragen, erstellen, ändern und löschen.
  3. AngularJS ruft auf REST API auf um die Daten abzufragen und die Daten auf die Interface anzuzeigen. AngularJS ruft auf REST API auf um die Daten zu löschen, erstellen und bearbeiten.
In der letzten Unterricht werde ich die Applikation laufen und den Operationsgrundsatz von  AngularJS in jeder bestimmten Funktion erklären.

2- Das Projekt Spring Boot erstellen

Auf  Eclipse erstelen Sie ein Projekt  Spring Boot:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
    http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.o7planning</groupId>
    <artifactId>SpringBootAngularJS</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>SpringBootAngularJS</name>
    <description>Spring Boot + AngularJS</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
application.properties
spring.thymeleaf.cache=false
SpringBootAngularJsApplication.java
package org.o7planning.sbangularjs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootAngularJsApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootAngularJsApplication.class, args);
    }
}

3- Model, DAO

Employee.java
package org.o7planning.sbangularjs.model;

public class Employee {

    private Long empId;
    private String empNo;
    private String empName;
    private String position;

    public Employee() {

    }

    public Employee(EmployeeForm empForm) {
        this.empId = empForm.getEmpId();
        this.empNo = empForm.getEmpNo();
        this.empName = empForm.getEmpName();
        this.position = empForm.getPosition();
    }

    public Employee(Long empId, String empNo, String empName, String position) {
        this.empId = empId;
        this.empNo = empNo;
        this.empName = empName;
        this.position = position;
    }

    public Long getEmpId() {
        return empId;
    }

    public void setEmpId(Long empId) {
        this.empId = empId;
    }

    public String getEmpNo() {
        return empNo;
    }

    public void setEmpNo(String empNo) {
        this.empNo = empNo;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

}
EmployeeForm.java
package org.o7planning.sbangularjs.model;

public class EmployeeForm {
    
    private Long empId;
    private String empNo;
    private String empName;
    private String position;

    public Long getEmpId() {
        return empId;
    }

    public void setEmpId(Long empId) {
        this.empId = empId;
    }

    public String getEmpNo() {
        return empNo;
    }

    public void setEmpNo(String empNo) {
        this.empNo = empNo;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }
}
EmployeeDAO.java
package org.o7planning.sbangularjs.dao;
 
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
import org.o7planning.sbangularjs.model.Employee;
import org.o7planning.sbangularjs.model.EmployeeForm;
import org.springframework.stereotype.Repository;
 
@Repository
public class EmployeeDAO {
 
    private static final Map<Long, Employee> empMap = new HashMap<Long, Employee>();
 
    static {
        initEmps();
    }
 
    private static void initEmps() {
        Employee emp1 = new Employee(1L, "E01", "Smith", "Clerk");
        Employee emp2 = new Employee(2L, "E02", "Allen", "Salesman");
        Employee emp3 = new Employee(3L, "E03", "Jones", "Manager");
 
        empMap.put(emp1.getEmpId(), emp1);
        empMap.put(emp2.getEmpId(), emp2);
        empMap.put(emp3.getEmpId(), emp3);
    }
 
    public Long getMaxEmpId() {
        Set<Long> keys = empMap.keySet();
        Long max = 0L;
        for (Long key : keys) {
            if (key > max) {
                max = key;
            }
        }
        return max;
    }
 
    public Employee getEmployee(Long empId) {
        return empMap.get(empId);
    }
 
    public Employee addEmployee(EmployeeForm empForm) {
        Long empId= this.getMaxEmpId()+ 1;
        empForm.setEmpId(empId);
        Employee newEmp = new Employee(empForm);  
        
        empMap.put(newEmp.getEmpId(), newEmp);
        return newEmp;
    }
 
    public Employee updateEmployee(EmployeeForm empForm) {
        Employee emp = this.getEmployee(empForm.getEmpId());
        if(emp!= null)  {
            emp.setEmpNo(empForm.getEmpNo());
            emp.setEmpName(empForm.getEmpName());
            emp.setPosition(empForm.getPosition());
        }  
        return emp;
    }
 
    public void deleteEmployee(Long empId) {
        empMap.remove(empId);
    }
 
    public List<Employee> getAllEmployees() {
        Collection<Employee> c = empMap.values();
        List<Employee> list = new ArrayList<Employee>();
        list.addAll(c);
        return list;
    }
 
}

4- Controller, Rest Controller

MainController.java
package org.o7planning.sbangularjs.controller;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller
public class MainController {
 
    @RequestMapping("/")
    public String welcome() {
        return "index";
    }
}
MainRESTController.java
package org.o7planning.sbangularjs.controller;
 
import java.util.List;
 
import org.o7planning.sbangularjs.dao.EmployeeDAO;
import org.o7planning.sbangularjs.model.Employee;
import org.o7planning.sbangularjs.model.EmployeeForm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
 
@RestController  
public class MainRESTController {
 
    @Autowired
    private EmployeeDAO employeeDAO;
 
 
    // URL:
    // http://localhost:8080/SomeContextPath/employees
    // http://localhost:8080/SomeContextPath/employees.xml
    // http://localhost:8080/SomeContextPath/employees.json
    @RequestMapping(value = "/employees", //
            method = RequestMethod.GET, //
            produces = { MediaType.APPLICATION_JSON_VALUE, //
                    MediaType.APPLICATION_XML_VALUE })
    @ResponseBody
    public List<Employee> getEmployees() {
        List<Employee> list = employeeDAO.getAllEmployees();
        return list;
    }
 
    // URL:
    // http://localhost:8080/SomeContextPath/employee/{empId}
    // http://localhost:8080/SomeContextPath/employee/{empId}.xml
    // http://localhost:8080/SomeContextPath/employee/{empId}.json
    @RequestMapping(value = "/employee/{empId}", //
            method = RequestMethod.GET, //
            produces = { MediaType.APPLICATION_JSON_VALUE, //
                    MediaType.APPLICATION_XML_VALUE })
    @ResponseBody
    public Employee getEmployee(@PathVariable("empId") Long empId) {
        return employeeDAO.getEmployee(empId);
    }
 
    // URL:
    // http://localhost:8080/SomeContextPath/employee
    // http://localhost:8080/SomeContextPath/employee.xml
    // http://localhost:8080/SomeContextPath/employee.json
 
    @RequestMapping(value = "/employee", //
            method = RequestMethod.POST, //
            produces = { MediaType.APPLICATION_JSON_VALUE, //
                    MediaType.APPLICATION_XML_VALUE })
    @ResponseBody
    public Employee addEmployee(@RequestBody EmployeeForm empForm) {
 
        System.out.println("(Service Side) Creating employee with empNo: " + empForm.getEmpNo());
 
        return employeeDAO.addEmployee(empForm);
    }
 
    // URL:
    // http://localhost:8080/SomeContextPath/employee
    // http://localhost:8080/SomeContextPath/employee.xml
    // http://localhost:8080/SomeContextPath/employee.json
    @RequestMapping(value = "/employee", //
            method = RequestMethod.PUT, //
            produces = { MediaType.APPLICATION_JSON_VALUE, //
                    MediaType.APPLICATION_XML_VALUE })
    @ResponseBody
    public Employee updateEmployee(@RequestBody EmployeeForm empForm) {
 
        System.out.println("(Service Side) Editing employee with Id: " + empForm.getEmpId());
 
        return employeeDAO.updateEmployee(empForm);
    }
 
    // URL:
    // http://localhost:8080/SomeContextPath/employee/{empId}
    @RequestMapping(value = "/employee/{empId}", //
            method = RequestMethod.DELETE, //
            produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
    @ResponseBody
    public void deleteEmployee(@PathVariable("empId") Long empId) {
 
        System.out.println("(Service Side) Deleting employee with Id: " + empId);
 
        employeeDAO.deleteEmployee(empId);
    }
 
}

5- Javascript, Css, View

index.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
   <head>
      <title>AngularJS</title>
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.js"></script>
      
      <script th:src="@{/main.js}"></script>
      <link th:href="@{/main.css}" rel="stylesheet" />
      
      <head>
   <body ng-app="EmployeeManagement" ng-controller="EmployeeController">
      <h3>
         CRUD: Spring Boot + Rest + AngularJS
      </h3>
      <form ng-submit="submitEmployee()">
         <table border="0">
            <tr>
               <td>Emp Id</td>
               <td>{{employeeForm.empId}}</td>
            </tr>
            <tr>
               <td>Emp No</td>
               <td><input type="text" ng-model="employeeForm.empNo" /></td>
            </tr>
            <tr>
               <td>Emp Name</td>
               <td><input type="text" ng-model="employeeForm.empName"  /></td>
            </tr>
            <tr>
               <td colspan="2">
                  <input type="submit" value="Submit" class="blue-button" />
               </td>
            </tr>
         </table>
      </form>
      <br/>
      <a class="create-button" ng-click="createEmployee()">Create Employee</a>
      <table border="1">
         <tr>
            <th>Emp Id</th>
            <th>Emp No</th>
            <th>Emp Name</th>
            <th>Edit</th>
            <th>Delete</th>
         </tr>
         <!-- $scope.employees -->
         <tr ng-repeat="employee in employees">
            <td> {{ employee.empId }}</td>
            <td> {{ employee.empNo }}</td>
            <td >{{ employee.empName }}</td>
            <td>
            <a ng-click="editEmployee(employee)" class="edit-button">Edit</a>
            </td>
            <td>
            <a ng-click="deleteEmployee(employee)" class="delete-button">Delete</a>
            </td>
         </tr>
      </table>
   </body>
</html>
main.css
table  {
    border-collapse: collapse;
}

table td, th  {
    padding: 5px;
}

.create-button  {
    color: blue;
    cursor: pointer;
    padding: 5px;
}
.edit-button  {
    padding: 2px 5px;
    background: #25A6E1;
    cursor: pointer;
}

.delete-button  {
    padding: 2px 5px;
    background: #CD5C5C;
    cursor: pointer;
}
main.js
var app = angular.module("EmployeeManagement", []);

// Controller Part
app.controller("EmployeeController", function($scope, $http) {


    $scope.employees = [];
    $scope.employeeForm = {
        empId: 1,
        empNo: "",
        empName: ""
    };

    // Now load the data from server
    _refreshEmployeeData();

    // HTTP POST/PUT methods for add/edit employee  
    // Call: http://localhost:8080/employee
    $scope.submitEmployee = function() {

        var method = "";
        var url = "";

        if ($scope.employeeForm.empId == -1) {
            method = "POST";
            url = '/employee';
        } else {
            method = "PUT";
            url = '/employee';
        }

        $http({
            method: method,
            url: url,
            data: angular.toJson($scope.employeeForm),
            headers: {
                'Content-Type': 'application/json'
            }
        }).then(_success, _error);
    };

    $scope.createEmployee = function() {
        _clearFormData();
    }

    // HTTP DELETE- delete employee by Id
    // Call: http://localhost:8080/employee/{empId}
    $scope.deleteEmployee = function(employee) {
        $http({
            method: 'DELETE',
            url: '/employee/' + employee.empId
        }).then(_success, _error);
    };

    // In case of edit
    $scope.editEmployee = function(employee) {
        $scope.employeeForm.empId = employee.empId;
        $scope.employeeForm.empNo = employee.empNo;
        $scope.employeeForm.empName = employee.empName;
    };

    // Private Method  
    // HTTP GET- get all employees collection
    // Call: http://localhost:8080/employees
    function _refreshEmployeeData() {
        $http({
            method: 'GET',
            url: '/employees'
        }).then(
            function(res) { // success
                $scope.employees = res.data;
            },
            function(res) { // error
                console.log("Error: " + res.status + " : " + res.data);
            }
        );
    }

    function _success(res) {
        _refreshEmployeeData();
        _clearFormData();
    }

    function _error(res) {
        var data = res.data;
        var status = res.status;
        var header = res.header;
        var config = res.config;
        alert("Error: " + status + ":" + data);
    }

    // Clear the form
    function _clearFormData() {
        $scope.employeeForm.empId = -1;
        $scope.employeeForm.empNo = "";
        $scope.employeeForm.empName = ""
    };
});

6- Den Operationsgrundsatz erklären

OK, jetzt können Sie die Applikation laufen und sehen wie  AngularJS in jeder bestimmten Funktion

Die Funktion von der Anzeige der Mitarbeitersliste

Wenn die Webseite läuft, wird  AngularJS auf  REST API aufrufen um die Liste von Mitarbeiter zu entnehmen. Die Daten wird auf die Variable  $scope.employees gelagert. Und  AngularJS wird sie in die Interface anzeigen. Wenn die Daten von  $scope.employees ändert, wird  AngularJS automatically die Interface aktualisieren.
AngularJS ruft auf  REST API auf um die Liste der Mitarbeiter (Employee) zu nehmen und die genommenen Daten in der Variable  $scope.employees ​​​​​​​zu lagern.
// Private Method  
// HTTP GET- get all employees collection
// Call: http://localhost:8080/employees
function _refreshEmployeeData() {
    $http({
        method: 'GET',
        url: '/employees'
    }).then(
        function(res) { // success
            $scope.employees = res.data;
        },
        function(res) { // error
            console.log("Error: " + res.status + " : " + res.data);
        }
    );
}

.....
AngularJS zeigt die Daten in der Variable  $scope.employees in die Interface an:
<table border="1">
   <tr>
      <th>Emp Id</th>
      <th>Emp No</th>
      <th>Emp Name</th>
      <th>Edit</th>
      <th>Delete</th>
   </tr>
   <!-- $scope.employees -->
   <tr ng-repeat="employee in employees">
      <td> {{ employee.empId }}</td>
      <td> {{ employee.empNo }}</td>
      <td >{{ employee.empName }}</td>
      <td>
         <a ng-click="editEmployee(employee)" class="edit-button">Edit</a>
      </td>
      <td>
         <a ng-click="deleteEmployee(employee)" class="delete-button">Delete</a>
      </td>
   </tr>
</table>

Die Funktion zur Bearbeitung der Information von Mitarbeiter:

AngularJS kann zweiseitig die Daten zwischen   Model und  View binden (two-way binding). D.h wenn der Benutzer die Daten auf  View eingibt, wird diese Daten automatisch in  Model aktualisiert werden und umgekehrt wenn die Daten auf Model ändert, wird es auf View angezeigt.
AngularJS verwendet das Attribut (attribute) ng-model zur die zweiseitige Bindung (2-way binding) zwischen  Model und  View:
<form ng-submit="submitEmployee()">
   <table border="0">
      <tr>
         <td>Emp Id</td>
         <td>{{employeeForm.empId}}</td>
      </tr>
      <tr>
         <td>Emp No</td>
         <td><input type="text" ng-model="employeeForm.empNo" /></td>
      </tr>
      <tr>
         <td>Emp Name</td>
         <td><input type="text" ng-model="employeeForm.empName"  /></td>
      </tr>
      <tr>
         <td colspan="2">
            <input type="submit" value="Submit" class="blue-button" />
         </td>
      </tr>
   </table>
</form>
Der Benutzer klickt auf den Button  "Edit", und die Funktion  $scope.editEmployee wird aufgeruft
<a ng-click="editEmployee(employee)" class="edit-button">Edit</a>
Javascript:
// JavaScript: When user Click to Edit button:
$scope.editEmployee = function(employee) {
    $scope.employeeForm.empId = employee.empId;
    $scope.employeeForm.empNo = employee.empNo;
    $scope.employeeForm.empName = employee.empName;
};

// SAVE !!
// HTTP POST/PUT methods for add/edit employee  
// Call: http://localhost:8080/employee
$scope.submitEmployee = function() {

    var method = "";
    var url = "";

    if ($scope.employeeForm.empId == -1) {
        method = "POST";
        url = '/employee';
    } else {
        method = "PUT";
        url = '/employee';
    }

    $http({
        method: method,
        url: url,
        data: angular.toJson($scope.employeeForm),
        headers: {
            'Content-Type': 'application/json'
        }
    }).then(_success, _error);
};

Die Funktion von der Löschung der Mitarbeiter (Employee):

Um einen Mitarbeiter (Employee) zu löschen, ruft  AngularJS auf  REST API auf um die Löschung eines Mitarbeiter zu anfordern. Wenn erfolgreich, wird es auf  REST API weiter aufrufen um die Liste der Mitarbeiter abzufragen und in die Interface anzuzeigen.
// HTTP DELETE- delete employee by Id
// Call: http://localhost:8080/employee/{empId}
$scope.deleteEmployee = function(employee) {
    $http({
        method: 'DELETE',
        url: '/employee/' + employee.empId
    }).then(_success, _error);
};

.....


function _success(res) {
     _refreshEmployeeData();
     _clearFormData();
 }

 function _error(res) {
     var data = res.data;
     var status = res.status;
     var header = res.header;
     var config = res.config;
     alert("Error: " + status + ":" + data);
 }

7- Bonus: Die Funktion success und error

Im  AngularJS gibt es 2 Maßnahmen um die Funktion  success und  error zu benutzen:
  1. Die Funktion success & error mit einem Parameter
  2. Die Funktion success & error mit 4 Paramater
  • success & error with 1 parameter:

$http.get('/someURL').then(
    // Success
    function(response) {
        var data = response.data;
        var status = response.status;
        var header = response.header;
        var config = response.config;
        // ...
    },
    // Error
    function(response) {
        var data = response.data;
        var status = response.status;
        var header = response.header;
        var config = response.config;
        // ...
    }
);
  • success & error with 4 parameters:

$http.get('/someURL')
    // Success
    .success(
        function(data, status, header, config) {
            // ...
        }
    )
    // Error
    .error(
        function(data, status, header, config) {
            // error handler
        }
    );

View more categories: