В этом руководстве я собираюсь создать приложение-службу RESTful с помощью spring -boot, spring-jpa, hsqldb, AngularJs.

Вы можете просмотреть исходную статью на моем личном сайте и скачать исходный текст с Github.

Maven - единственное требование для этого руководства. Вы также можете использовать IDE, например Eclipse. В настоящее время у меня Eclipse Neon for Java EE Developers

Наброски

Раздел 1: Создание проекта с использованием Spring Initializr

Давайте сначала создадим структуру нашего проекта, используя SPRING INITIALIZR из https://start.spring.io/

Я собираюсь создать проект Maven с помощью Spring Boot 1.4.0 (которые выбраны по умолчанию).

Второй шаг - написать название группы для проекта. Мой com.ferdisonmezay, а артефакт issuetracker

Таким образом, имена пакетов этого проекта будут начинаться с com.ferdisonmezay.issuetracker

Затем нам нужно выбрать зависимости: вы можете сделать это, введя имена в текстовое поле «Зависимости», или вы также можете щелкнуть ссылку «Перейти к полной версии» и выбрать все зависимости, которые вы хотите использовать.

Для этого приложения я буду использовать:

  • Интернет
  • Джерси (JAX-RS)
  • JPA
  • HSQLDB

После выбора этих зависимостей нажмите кнопку Generate Project. Файлы вашего проекта будут сгенерированы и загружены.

Теперь извлеките загруженный zip-файл и cd в распакованную папку и запустите

mvn spring-boot:run

Наше приложение весенней загрузки должно быть запущено. Теперь, если вы откроете свой веб-браузер и перейдете по адресу http: // localhost: 8080 /, вы увидите страницу с ошибкой Whitelabel, что означает, что наше приложение запущено, и мы еще ничего не сопоставили.

Сейчас я делаю фиксацию в github, Сообщение о фиксации: исходный проект, загруженный с spring.io

Раздел 2: Создание веб-интерфейса

При весенней загрузке веб-приложений мы также можем обслуживать веб-сайты. Нам нужно поместить файлы, относящиеся к нашему веб-интерфейсу, в папку src/main/resources/static.

Я скопирую файлы css, javascript, image в статическую папку. Затем я создам индексный файл для отображения содержания веб-сайта.

Вот структура папок после копирования и вставки.

static
├── css
│   ├── font-awesome.min.css #for icons etc.
│   └── main.css #for UI styling
├── fonts
│   ├── FontAwesome.otf
│   ├── fontawesome-webfont.eot
│   ├── fontawesome-webfont.svg
│   ├── fontawesome-webfont.ttf
│   ├── fontawesome-webfont.woff
│   └── fontawesome-webfont.woff2
├── images
│   ├── banner.jpg
│   ├── logo.png
│   └── logo_big.png
└── js
    ├── angular-route.js
    ├── angular.min.js
    ├── bootstrap.min.js
    ├── custom.js # website custom js functions for scroll animations etc.
    ├── jquery-1.12.4.min.js
    └── jquery.easing.min.js

теперь нам нужно создать index.html файл в папке static.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Ferdi Sönmezay | Rest Application</title>
    <script type="text/javascript" src="./js/angular.min.js"></script>
    <script type="text/javascript" src="./js/angular-route.js"></script>
    <link rel="stylesheet" href="./css/main.css">
    <link rel="stylesheet" href="./css/font-awesome.min.css">
    <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
       <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
       <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
   <![endif]-->
</head>
  <body>
    <header class="site-header">
      <div class="wrapper">
        <nav class="navbar navbar-default navbar-fixed-top" id="mysiteNav">
          <div class="container">
            <div class="row">
              <div class="col-md-4 col-sm-4 col-xs-12 col-lg-4">
                <div class="navbar-header">
                  <button type="button" class="no-space navbar-toggle collapsed pull-right" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                    <i class="ion-navicon collapsed pull-right"></i>
                  </button>
                  <a class="navbar-brand-logo" href="./">
                    <div class="row">
                      <div class="col-md-1 col-sm-1 col-xs-1 col-lg-1">
                        <div class="logo">
                        	<img src="./images/logo.png">
                        </div>
                      </div>
                      <div class="col-md-11 col-sm-11 col-xs-11 col-lg-11">
                        <div class="brand collapse navbar-collapse">
                        	FERDİ SÖNMEZAY
                        	<p>Restapp</p>
                        </div>
                      </div>
                    </div>
                  </a>
                </div>
              </div>
              <div class="col-md-8 col-sm-8 col-xs-12 col-lg-8">
                <div id="navbar" class="collapse navbar-collapse">
                  <ul class="nav navbar-nav pull-right">
                    <li><a class="page-scroll" href="#/home">Home</a></li>
                    <li><a class="page-scroll" href="#/developer">Developers</a></li>
                    <li><a class="page-scroll" href="#/bug">Bugs</a></li>
                    <li><a class="page-scroll" href="#/story">Stories</a></li>
                    <li><a class="page-scroll" href="#/assign">Assign</a></li>
                  </ul>
                </div>
              </div>
            </div>
          </div>
        </nav>
      </div>
    </header>
    <div class="page-banner no-spacing paralax" data-speed="2" style="background-image: url('images/banner.jpg');">
      <div class="bg-overlay no-spacing paralax">
        <div class="container header-container text-center">
            <h3>
                REST API for an issue tracker of a small team of developers
            </h3>
        </div>
      </div>
    </div>
    <div class="page-wrap" id="page-wrap">
      <div class="container">
        <div class="page-content">
          <div class="wrapper">
            Content will be displayed here
          </div>
        </div>
      </div>
    </div>
    <footer class="site-footer">
      <div class="container">
        <div class="row">
          <div class="col-md-8 col-sm-8 col-xs-12 col-lg-8">
            <div>
              <ul>
                <li><a class="page-scroll" href="#/home">Home</a></li>
                <li><a class="page-scroll" href="#/developer">Developers</a></li>
                <li><a class="page-scroll" href="#/bug">Bugs</a></li>
                <li><a class="page-scroll" href="#/story">Stories</a></li>
                <li><a class="page-scroll" href="#/assign">Assign</a></li>
              </ul>
            </div>
          </div>
        </div>
      </div>
    </footer>
  </body>
  <script type="text/javascript" src="./js/jquery-1.12.4.min.js"></script>
  <script type="text/javascript" src="./js/bootstrap.min.js"></script>
  <script type="text/javascript" src="./js/custom.js"></script>
</html>

Вот второй коммит для исходного веб-интерфейса.

Теперь нам нужно создать файл приложения AngularJs с именем restapp.js в папке js.

//js/restapp.js
(function() {
    var app = angular.module('restapp', ['ngRoute']);
    app.config(['$routeProvider', function($routeProvider) {
        $routeProvider.
        when('/home', {
                templateUrl: 'partials/main.html',
                controller: 'MainController'
            })
            .otherwise({
                redirectTo: '/home'
            });
    }]);

    app.controller('MainController', ['$scope', function($scope) {
    }]);

    /** DEVELOPERS **/
    /** BUGS **/
    /** STORIES **/
    /** ASSIGNMENTS **/

})();

нам также нужно добавить функциональность angularjs в наш index.html файл.

Сначала измените <html> на <html data-ng-app="restapp">

Затем измените <div class="wrapper">Content will be displayed here</div> на

<div class="wrapper" ng-controller="MainController">
  <ng-view></ng-view>
</div>

и добавьте <script type="text/javascript" src="./js/restapp.js"></script> после

<script type="text/javascript" src="./js/angular.min.js"></script>
<script type="text/javascript" src="./js/angular-route.js"></script>
<!--add restapp-->
<script type="text/javascript" src="./js/restapp.js"></script>

Наконец, нам нужно добавить html-страницу для отображения содержимого на главной странице. Я назову этот файл main.html и сохраню его в static/partials/ папку.

<div class="row">
    <div class="text-left col-sm-6 col-md-3 col-lg-3 col-xl-2 no-space" style="padding: 0px 10px;">
        <div class="thumbnail">
            <div class="text-center" style="font-size:36pt;">
                <i class="fa fa-users"></i>
            </div>
            <div class="caption" style="padding:20px;">
                <h5 class="post-caption text-center">
                    <a class="" href="#/developer">Developers</a>
                </h5>
                <p style="font-size:14px;">
                    You can add, remove or update developers in this section.
                    <a href="#/developer">Go</a><br><br>
                </p>
            </div>
        </div>
    </div>
    <div class="text-left col-sm-6 col-md-3 col-lg-3 col-xl-2 no-space" style="padding: 0px 10px;">
        <div class="thumbnail">
            <div class="text-center" style="font-size:36pt;">
                <i class="fa fa-bug"></i>
            </div>
            <div class="caption" style="padding:20px;">
                <h5 class="post-caption text-center">
                    <a class="" href="#/bug">Bugs</a>
                </h5>
                <p style="font-size:14px;">
                    You can manage bugs in this section
                    <a href="#/bug">Go</a><br><br>
                </p>
            </div>
        </div>
    </div>
    <div class="text-left col-sm-6 col-md-3 col-lg-3 col-xl-2 no-space" style="padding: 0px 10px;">
        <div class="thumbnail">
            <div class="text-center" style="font-size:36pt;">
                <i class="fa fa-clone"></i>
            </div>
            <div class="caption" style="padding:20px;">
                <h5 class="post-caption text-center">
                    <a class="" href="#/story">Stories</a>
                </h5>
                <p style="font-size:14px;">
                    You can manage stories in this section
                    <a href="#/story">Go</a><br><br>
                </p>
            </div>
        </div>
    </div>
    <div class="text-left col-sm-6 col-md-3 col-lg-3 col-xl-2 no-space" style="padding: 0px 10px;">
        <div class="thumbnail">
            <div class="text-center" style="font-size:36pt;">
                <i class="fa fa-connectdevelop" aria-hidden="true"></i>
            </div>
            <div class="caption" style="padding:20px;">
                <h5 class="post-caption text-center">
                    <a class="" href="#/assign">Assign</a>
                </h5>
                <p style="font-size:14px;">
                    Assign bugs and stories to developers
                    <a href="#/assign">Go</a><br><br>
                </p>
            </div>
        </div>
    </div>
</div>

теперь мы можем запустить наше приложение mvn spring-boot:run, и вы должны увидеть этот экран ниже.

Вот третий коммит добавления AngularJ в проект.

Раздел 3: Реализация функциональности «Разработчики»

В этом разделе в приложении будет три слоя:

  • Уровень контроллера
  • Уровень обслуживания
  • Репозиторий / Уровень Дао

Запросы от клиентов будут обрабатываться в контроллерах. Затем уровень обслуживания будет выполнять некоторые бизнес-логические операции, и, наконец, Dao или уровень репозитория будет обрабатывать операции с базой данных.

Сначала я создам пакет com.ferdisonmezay.issuetracker.entity для классов Entity. Затем я собираюсь создать два класса Java Entity.

У наших разработчиков будут только атрибуты id и name. Но поскольку в этом проекте каждая сущность будет иметь атрибут ìd, сначала я создам класс с именем BaseEntity.java и расширю этот класс из других классов сущностей.

Вот BaseEntity.java файл:

package com.ferdisonmezay.issuetracker.entity;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
@MappedSuperclass
public class BaseEntity {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name="ID")
  private Integer id;
  public Integer getId() { return id; }
  public void setId(Integer id) {	this.id = id; }
}

А вот и класс DeveloperEntity.java:

package com.ferdisonmezay.issuetracker.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name="DEVELOPERS")
public class DeveloperEntity extends BaseEntity {
  @Column(name="name")
  private String name;
  public DeveloperEntity() {}
  public DeveloperEntity(String name) { this.name = name; }
  public String getName() { return name; }
  public void setName(String name) { this.name = name; }
}

Затем для операций с базой данных я создам интерфейс с именем DeveloperDao.java в пакете com.ferdisonmezay.issuetracker.dao, который расширяет JpaRepository<EntityClass, Integer>.

package com.ferdisonmezay.issuetracker.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.ferdisonmezay.issuetracker.entity.DeveloperEntity;
@Repository
public interface DeveloperDao extends JpaRepository<DeveloperEntity, Integer> {
}

Этот класс не содержит никаких функций, мы будем использовать методы из класса JpaRepository.

В некоторых приложениях нет необходимости добавлять уровень обслуживания между контроллером и классами Dao, но я добавлю этот уровень. Возможно, некоторые из вас захотят добавить бизнес-логику в классы обслуживания.

Итак, вот файл DeveloperService.java в пакете com.ferdisonmezay.issuetracker.service.

package com.ferdisonmezay.issuetracker.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ferdisonmezay.issuetracker.dao.DeveloperDao;
import com.ferdisonmezay.issuetracker.entity.DeveloperEntity;
@Service
public class DeveloperService{
  @Autowired
  private DeveloperDao developerDao;
  public DeveloperEntity add(String name) {
    DeveloperEntity developer = new DeveloperEntity(name);
    return developerDao.save(developer);
  }
  public List<DeveloperEntity> getDevelopers(){ return developerDao.findAll(); }
  public DeveloperEntity getById(Integer id) { return developerDao.findOne(id); }
  public DeveloperEntity update(DeveloperEntity developer) { return developerDao.save(developer); }
  public void delete(Integer developerId) { developerDao.delete(developerId); }
  public Long getDeveloperCount() { return developerDao.count(); }
}

Наконец, нам нужно создать наши RESTful-сервисы. Для обработки запросов я создам DeveloperController.java с пометкой @RestController в пакете com.ferdisonmezay.issuetracker.controller

package com.ferdisonmezay.issuetracker.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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.RestController;
import com.ferdisonmezay.issuetracker.entity.DeveloperEntity;
import com.ferdisonmezay.issuetracker.service.DeveloperService;
@RestController
@RequestMapping("/developer")
public class DeveloperController {
  @Autowired
  private DeveloperService developerService;
  @RequestMapping(value="list", method = RequestMethod.GET)
  public List<DeveloperEntity> getDeveloperList() {
    return developerService.getDevelopers();
  }
  @RequestMapping(value = "create", method = RequestMethod.POST)
  public DeveloperEntity create(@RequestBody String name) {
    return developerService.add(name);
  }
  @RequestMapping(value = "update/{id}", method = RequestMethod.PUT)
  public DeveloperEntity update(@RequestBody DeveloperEntity developer) {
    return developerService.update(developer);
  }
  @RequestMapping(value = "delete/{id}", method = RequestMethod.DELETE)
  public void delete(@PathVariable(value = "id") Integer developerId) {
    developerService.delete(developerId);
  }
}

Теперь нам нужно добавить раздел функций работы CRUD для разработчиков в файл AngularJs, который мы назвали restapp.js.

Сначала добавьте правило маршрутизации для developer url.

.when('/developer', {
      templateUrl: 'partials/developers.html',
      controller: 'DevelopersController'
  })

Затем добавьте функциональные возможности DevelopersController и DevelopersService. в restapp.js файл.

/** DEVELOPERS **/
app.controller('DevelopersController', ['$scope', 'DevelopersService', function($scope, DevelopersService) {
    function resetParams() {
        $scope.actionName = "New Developer";
        $scope.submitButtonLabel = "Insert";
        $scope.currentDeveloper = {
            id: null,
            "name": null
        };
        $scope.isFormClean = true;
        $scope.name = "";
    }
    function developerList() {
        DevelopersService.list()
            .then(function(response) {
                $scope.developers = response.data;
            });
    }
    function resetParamsAndLoadDeveloperList() {
        resetParams();
        developerList();
    }
    $scope.selectDeveloper = function(developer) {
        $scope.actionName = "Update Developer";
        $scope.submitButtonLabel = "Update";
        $scope.currentDeveloper = developer;
        $scope.name = $scope.currentDeveloper.name;
        $scope.isFormClean = false;
    };
    $scope.submit = function() {
        if ($scope.isFormClean) {
            $scope.insert($scope.name);
        } else  {
            $scope.currentDeveloper.name = $scope.name;
            $scope.update($scope.currentDeveloper);
        }
        resetParamsAndLoadDeveloperList();
    };
    $scope.insert = function(name) {
        DevelopersService.insert(name)
            .then(function(response) {
                resetParamsAndLoadDeveloperList();
            });
    };
    $scope.update = function(developer) {
        DevelopersService.update(developer)
            .then(function(response) {
                resetParamsAndLoadDeveloperList();
            });
    };
    $scope.delete = function(developerId) {
        DevelopersService.delete(developerId)
            .then(function(response) {
                resetParamsAndLoadDeveloperList();
            });
    };
    $scope.cancel = function() {
        resetParams();
    };
    resetParamsAndLoadDeveloperList();
}]);
app.service('DevelopersService', function($http) {
    var service = this;
    var path = '/developer/';
    function getPath() {
        return path;
    }
    function getUrl(action) {
        return getPath() + action;
    }
    service.list = function() {
        return $http.get(getUrl('list'));
    };
    service.insert = function(name) {
        return $http.post(getUrl('create'), name);
    };
    service.update = function(developer) {
        return $http.put(getUrl('update/' + developer.id), developer);
    };
    service.delete = function(id) {
        return $http.delete(getUrl('delete/' + id), {
            'id': id
        });
    };
});
/** BUGS **/

Наконец, добавьте html-файл в папку partials с именем developers.html, чтобы отобразить список разработчиков и выполнить операции CRUD с разработчиками.

<ol class="breadcrumb">
  <li><a href="#/home"><i class="fa fa-home" aria-hidden="true"></i></a></li>
  <li class="active">Developers</li>
</ol>
<div class="row" data-ng-controller="DevelopersController">
  <div class="col-md-6">
    <h4 class="text-center">Developers</h4>
    <div class="white-background" style="padding:15px;">
	    <table class="table table-hover table-condensed">
	      <thead>
	        <tr>
	          <th>#</th>
	          <th>Name</th>
	          <th>Actions</th>
	         </tr>
	      </thead>
	      <tbody>
	        <tr ng-repeat="developer in developers" ng-class="(developer.id == currentDeveloper.id) ? 'warning' : ''">
	          <td></td>
	          <td width="80%"></td>
		        <td  width="5%" style="text-align:center;">
	            <a class="btn btn-xs btn-success" ng-click="selectDeveloper(developer)"><i class="fa fa-pencil-square-o "></i></a>
		        </td>
	         </tr>        
	      </tbody>
	    </table>
    </div>
  </div>
  <div class="col-md-1"></div>
  <div class="col-md-5">
    <h4 style="color:#B80D57;"></h4>
    <div class="white-background" style="padding:20px;">
    <form name="developerForm" ng-submit="submit()" method="POST">
      <div class="row">
        <div class="col-md-12">
          <div class="form-group">
            <label class="control-label" for="name">Name</label>
            <input value="" name="name" id="name" type="text" ng-model="name" placeholder="" class="form-control">
          </div>
        </div>
      </div>
      <div class="row">
        <div class="col-md-12 text-right">
          <input class="btn btn-success btn-sm" type="submit" id="submit" value="" />
          <a ng-if="currentDeveloper.id" ng-click="delete(currentDeveloper.id)" class="btn btn-danger btn-sm">Delete</a>
          <a ng-if="currentDeveloper.id" ng-click="cancel()" class="btn btn-default btn-sm">Cancel</a>
        </div>
      </div>
    </form>
    </div>
  </div>
</div>

После последних изменений, когда вы нажимаете ссылку «РАЗРАБОТЧИКИ», вы должны увидеть экран, показанный ниже.

Далее следует коммит для добавления грубых операций разработчика.

Документация Swagger Rest API

См. SwaggerConfig.java файл для документации по API Swagger rest.

Вы можете просмотреть документацию по API и протестировать API с помощью swagger-ui, доступ к которому можно получить по адресу: http: // localhost: 8080 / swagger-ui.html после запуска приложения.

Инициализация и хранение данных

Исходные данные загружаются в приложение из файла import.sql. Это приложение использует HSQLDB в качестве базы данных, когда вы запускаете приложение, выполняются все сценарии из указанного файла, и данные импортируются в приложение.

Примечание. При остановке приложения данные, вставленные с помощью пользовательского интерфейса, будут потеряны.

Резюме

В этом руководстве я создал приложение для весенней загрузки и объяснил, как создать веб-приложение на Java с помощью фреймворка Spring и AngularJs.

Учебник содержит только раздел «Разработчики», в который вы можете добавлять, обновлять, удалять и просматривать разработчиков. Я также добавил функции для создания, обновления и удаления ошибок и историй. Также есть страница для автоматического назначения историй разработчикам.

Вы можете получить последний исходный код на Github.