Рубрики
Без рубрики

Создание веб – приложения с помощью Spring Boot и Angular

Взгляните на создание веб-приложения с бэкэндом Spring REST и угловым интерфейсом.

Автор оригинала: Alejandro Ugarte.

1. Обзор

Spring Boot и Angular образуют мощный тандем, который отлично подходит для разработки веб-приложений с минимальными затратами.

В этом уроке мы будем использовать Spring Boot для реализации RESTful backend и Angular для создания интерфейса на основе JavaScript.

Дальнейшее чтение:

Контроллеры с интерфейсом весной

Spring REST API + OAuth2 + Угловой

2. Приложение Spring Boot

Функциональность нашего демонстрационного веб – приложения действительно будет довольно упрощенной. Он будет просто сужен до извлечения и отображения Списка сущностей JPA из базы данных H2 в памяти и сохранения новых сущностей в простой HTML-форме.

2.1. Зависимости Maven

Вот зависимости нашего проекта Spring Boot:

 
    org.springframework.boot 
    spring-boot-starter-web 

 
    org.springframework.boot 
    spring-boot-starter-data-jpa 


    com.h2database
    h2
    runtime

Обратите внимание, что мы включили spring-boot-starter-web , потому что мы будем использовать его для создания службы REST, и spring-boot-starter-jpa для реализации уровня персистентности.

Версия H2 database также управляется родителем Spring Boot.

2.2. Класс сущностей JPA

Чтобы быстро создать прототип доменного уровня нашего приложения, давайте определим простой класс сущностей JPA, который будет отвечать за моделирование пользователей:

@Entity
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private final String name;
    private final String email;
    
    // standard constructors / setters / getters / toString
}

2.3. Пользовательский интерфейс

Поскольку нам понадобится базовая функциональность CRUD для сущностей User , мы также должны определить интерфейс UserRepository :

@Repository
public interface UserRepository extends CrudRepository{}

2.4. Контроллер REST

Теперь давайте реализуем REST API. В данном случае это просто простой контроллер ОТДЫХА.

@RestController
@CrossOrigin(origins = "http://localhost:4200")
public class UserController {

    // standard constructors
    
    private final UserRepository userRepository;

    @GetMapping("/users")
    public List getUsers() {
        return (List) userRepository.findAll();
    }

    @PostMapping("/users")
    void addUser(@RequestBody User user) {
        userRepository.save(user);
    }
}

В определении класса UserController нет ничего сложного по своей сути.

Конечно, единственная деталь реализации, которую стоит отметить здесь, – это использование @CrossOrigin аннотации . Как следует из названия, аннотация позволяет Совместное использование ресурсов между источниками (CORS) на сервере.

Этот шаг не всегда необходим. Поскольку мы развертываем наш угловой интерфейс в http://localhost:4200 и наш загрузочный сервер http://localhost:8080 , в противном случае браузер будет отклонять запросы от одного к другому.

Что касается методов контроллера, get User() извлекает все сущности User из базы данных. Аналогично, метод addUser() сохраняет новую сущность в базе данных, которая передается в теле запроса .

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

2.5. Загрузка приложения Spring Boot

Наконец, давайте создадим стандартный класс начальной загрузки Spring Boot и заполним базу данных несколькими сущностями User :

@SpringBootApplication
public class Application {

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

    @Bean
    CommandLineRunner init(UserRepository userRepository) {
        return args -> {
            Stream.of("John", "Julie", "Jennifer", "Helen", "Rachel").forEach(name -> {
                User user = new User(name, name.toLowerCase() + "@domain.com");
                userRepository.save(user);
            });
            userRepository.findAll().forEach(System.out::println);
        };
    }
}

Теперь давайте запустим приложение. Как и ожидалось, мы должны увидеть список сущностей User , распечатанный на консоли при запуске:

User{id=1, name=John, [email protected]}
User{id=2, name=Julie, [email protected]}
User{id=3, name=Jennifer, [email protected]}
User{id=4, name=Helen, [email protected]}
User{id=5, name=Rachel, [email protected]}

3. Угловое применение

Теперь, когда наше демо-приложение Spring Boot запущено и запущено, давайте создадим простое угловое приложение, способное использовать API контроллера REST.

3.1. Угловая установка CLI

Мы будем использовать Angular CLI , мощную утилиту командной строки, для создания нашего приложения Angular.

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

Как только мы установим npm (Диспетчер пакетов узлов), мы откроем командную консоль и введем команду:

npm install -g @angular/[email protected]

Вот и все. Приведенная выше команда установит последнюю версию Angular CLI.

3.2. Проектные строительные леса с угловым CLI

На самом деле, мы можем создать нашу структуру углового приложения с нуля. Но, честно говоря, это подверженная ошибкам и трудоемкая задача, которой мы должны избегать во всех случаях.

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

ng new angularclient

Команда new создаст всю структуру приложения в каталоге angular client .

3.3. Точка входа Углового Приложения

Если мы заглянем в папку angular client , то увидим, что Angular CLI фактически создал для нас целый проект.

Файлы угловых приложений используют TypeScript , типизированный надмножество JavaScript, который компилируется в обычный JavaScript. Однако точка входа любого углового приложения-это обычная старая index.html файл.

Давайте отредактируем этот файл следующим образом:





  
  Spring Boot - Angular Application
  
  
  
  


  

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

Пожалуйста, обратите внимание на пользовательские теги внутри раздела . На первый взгляд они выглядят довольно странно, так как не является стандартным элементом HTML5.

Давайте оставим их там, так как | | – это корневой селектор, который Angular использует для рендеринга корневого компонента приложения .

3.4. Корневой компонент app.component.ts

Чтобы лучше понять, как Angular связывает HTML – шаблон с компонентом, давайте перейдем в каталог src/app и отредактируем файл app.component.ts TypeScript-корневой компонент:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  title: string;

  constructor() {
    this.title = 'Spring Boot - Angular Application';
  }
}

По понятным причинам мы не будем углубляться в изучение машинописного текста. Тем не менее, давайте заметим, что файл определяет класс AppComponent , который объявляет поле title типа string (в нижнем регистре). Определенно, это типизированный JavaScript.

Кроме того, конструктор инициализирует поле значением string , что очень похоже на то, что мы делаем в Java.

Наиболее важной частью является компонент @ |/маркер метаданных или декоратор , который определяет три элемента:

  1. селектор – селектор HTML, используемый для привязки компонента к файлу шаблона HTML
  2. templateUrl – файл шаблона HTML, связанный с компонентом
  3. styleUrls – один или несколько CSS-файлов, связанных с компонентом

Как и ожидалось, мы можем использовать app.component.html и app.component.css файлы для определения шаблона HTML и стилей CSS корневого компонента.

Наконец, элемент selector связывает весь компонент с селектором, включенным в index.html файл.

3.5. app.component.html Файл

С тех пор как app.component.html файл позволяет нам определить HTML — шаблон корневого компонента — класс AppComponent – мы будем использовать его для создания базовой панели навигации с двумя кнопками.

Если мы нажмем первую кнопку, Angular отобразит таблицу, содержащую список User сущностей, хранящихся в базе данных. Аналогично, если мы нажмем на второй, он отобразит HTML-форму, которую мы можем использовать для добавления новых сущностей в базу данных:

{{ title }}

Основная часть файла-стандартный HTML, с несколькими оговорками, которые стоит отметить.

Первый-это выражение {{ title }} . Двойные фигурные скобки {{ имя переменной}} – это заполнитель, который Angular использует для выполнения интерполяции переменных .

Давайте иметь в виду, что класс AppComponent инициализировал поле title значением Spring Boot – Angular Application . Таким образом, Angular отобразит значение этого поля в шаблоне. Аналогично, изменение значения в конструкторе будет отражено в шаблоне.

Второе, что следует отметить, – это ссылка маршрутизатора атрибут .

Angular использует этот атрибут для маршрутизации запросов через свой модуль маршрутизации (подробнее об этом позже). На данный момент достаточно знать, что модуль отправит запрос на /users путь к определенному компоненту и запрос на /adduser к другому компоненту.

В каждом случае HTML-шаблон, связанный с соответствующим компонентом, будет отображаться в заполнителе .

3.6. Класс Пользователя

Поскольку наше приложение Angular будет извлекать и сохранять объекты User в базе данных, давайте реализуем простую модель домена с помощью TypeScript.

Давайте откроем консоль терминала и создадим каталог model :

ng generate class user

Угловой CLI создаст пустой User класс. Давайте заполним его несколькими полями:

export class User {
    id: string;
    name: string;
    email: string;
}

3.7. Сервис Обслуживания Пользователей

Теперь, когда наш клиентский домен User class уже установлен, давайте реализуем класс обслуживания, который выполняет запросы GET и POST к http://localhost:8080/users конечная точка.

Это позволит нам инкапсулировать доступ к контроллеру REST в один класс, который мы можем повторно использовать во всем приложении .

Давайте откроем консольный терминал, затем создадим каталог service и в этом каталоге выполним следующую команду:

ng generate service user-service

Теперь давайте откроем файл user.service.ts , который только что создал Angular CLI, и проведем его рефакторинг:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { User } from '../model/user';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class UserService {

  private usersUrl: string;

  constructor(private http: HttpClient) {
    this.usersUrl = 'http://localhost:8080/users';
  }

  public findAll(): Observable {
    return this.http.get(this.usersUrl);
  }

  public save(user: User) {
    return this.http.post(this.usersUrl, user);
  }
}

Нам не нужен солидный фон на TypeScript, чтобы понять, как работает класс UserService . Проще говоря, он инкапсулирует в многоразовом компоненте всю функциональность, необходимую для использования API контроллера REST, который мы реализовали до в Spring Boot.

Метод findAll() выполняет HTTP-запрос GET к http://localhost:8080/users конечная точка через Угловой HttpClient . Метод возвращает экземпляр Observable , содержащий массив объектов User .

Аналогично, метод save() выполняет HTTP-запрос POST к http://localhost:8080/users конечная точка.

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

Наконец, давайте обратим внимание на использование маркера @Injectable() метаданных. Это сигнализирует о том, что служба должна быть создана и введена через Инжекторы угловой зависимости .

3.8. Компонент UserListComponent

В этом случае класс User Service является тонким средним уровнем между службой REST и уровнем представления приложения. Поэтому нам необходимо определить компонент, ответственный за отображение списка сущностей User , сохраненных в базе данных.

Давайте откроем консоль терминала, затем создадим каталог user-list и сгенерируем компонент списка пользователей:

ng generate component user-list

Angular CLI создаст пустой класс компонентов, реализующий интерфейс ngOnInit . Интерфейс объявляет метод hook ngOnInit () , который вызывает Angular после завершения создания экземпляра реализующего класса, а также после вызова его конструктора.

Давайте рефакторингуем класс так, чтобы он мог принимать экземпляр User Service в конструкторе:

import { Component, OnInit } from '@angular/core';
import { User } from '../model/user';
import { UserService } from '../service/user.service';

@Component({
  selector: 'app-user-list',
  templateUrl: './user-list.component.html',
  styleUrls: ['./user-list.component.css']
})
export class UserListComponent implements OnInit {

  users: User[];

  constructor(private userService: UserService) {
  }

  ngOnInit() {
    this.userService.findAll().subscribe(data => {
      this.users = data;
    });
  }
}

Реализация класса UserListComponent довольно понятна. Он просто использует метод Userservice findAll() для извлечения всех сущностей, сохраненных в базе данных, и сохраняет их в поле users .

Кроме того, нам нужно отредактировать HTML-файл компонента, user-list.component.html, для создания таблицы, отображающей список сущностей:

# Name Email
{{ user.id }} {{ user.name }} {{ user.email }}

Обратите внимание на использование директивы *ngFor . Директива называется repeater , и мы можем использовать ее для итерации содержимого переменной и итеративного рендеринга HTML-элементов. В этом случае мы использовали его для динамического отображения строк таблицы.

Кроме того, мы использовали интерполяцию переменных для отображения id, |/имени и электронной почты каждого пользователя.

3.9. Компонент UserForm Компонент

Аналогично, нам нужно создать компонент, который позволит нам сохранить новый объект User в базе данных.

Давайте создадим каталог userform и введем следующее:

ng generate component user-form

Далее, давайте откроем файл userform.component.ts и добавим в UserForm Component class метод для сохранения объекта User :

import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { UserService } from '../service/user.service';
import { User } from '../model/user';

@Component({
  selector: 'app-user-form',
  templateUrl: './user-form.component.html',
  styleUrls: ['./user-form.component.css']
})
export class UserFormComponent {

  user: User;

  constructor(
    private route: ActivatedRoute, 
      private router: Router, 
        private userService: UserService) {
    this.user = new User();
  }

  onSubmit() {
    this.userService.save(this.user).subscribe(result => this.gotoUserList());
  }

  gotoUserList() {
    this.router.navigate(['/users']);
  }
}

В этом случае компонент UserForm также принимает экземпляр User Service в конструкторе, который метод onSubmit() использует для сохранения предоставленного объекта User .

Поскольку нам нужно повторно отобразить обновленный список сущностей после сохранения нового, мы вызываем метод getuserlist() после вставки, который перенаправляет пользователя на путь /users .

Кроме того, нам нужно отредактировать user-form.component.html файл и создайте HTML-форму для сохранения нового пользователя в базе данных:

Name is required
Email is required

На первый взгляд форма выглядит довольно стандартной. Но он инкапсулирует много угловой функциональности за кулисами.

Давайте обратим внимание на использование директивы ng Submit , которая вызывает метод onSubmit() при отправке формы .

Затем мы определили переменную template #UserForm , поэтому Angular автоматически добавляет директиву ngForm , которая позволяет нам отслеживать форму в целом .

Директива ngForm содержит элементы управления, созданные нами для элементов формы с директивой ng Model и атрибутом name , а также отслеживает их свойства, включая их состояние.

Директива ngModel предоставляет нам двустороннюю привязку данных функциональность между элементами управления формой и моделью домена на стороне клиента-классом User |.

Это означает, что данные, введенные в поля ввода формы, будут поступать в модель – и наоборот. Изменения в обоих элементах будут немедленно отражены с помощью манипуляции DOM.

Кроме того, ng Model позволяет нам отслеживать состояние каждого элемента управления формой и выполнять проверку на стороне клиента , добавляя к каждому элементу управления различные классы CSS и свойства DOM.

В приведенном выше HTML-файле мы использовали свойства, применяемые к элементам управления формой, только для отображения окна предупреждения, когда значения в форме были изменены.

3.10. Файл app-routing.module.ts

Хотя компоненты функционируют изолированно, нам все равно необходимо использовать механизм их вызова, когда пользователь нажимает кнопки на панели навигации.

Именно здесь в игру вступает модуль маршрутизатора . Итак, давайте откроем файл app-routing.module.ts и настроим модуль, чтобы он мог отправлять запросы соответствующим компонентам:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { UserListComponent } from './user-list/user-list.component';
import { UserFormComponent } from './user-form/user-form.component';

const routes: Routes = [
  { path: 'users', component: UserListComponent },
  { path: 'adduser', component: UserFormComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Как мы видим выше, массив Routes указывает маршрутизатору, какой компонент должен отображаться, когда пользователь нажимает ссылку или указывает URL-адрес в адресной строке браузера.

Маршрут состоит из двух частей:

  1. Путь – a строка , соответствующая URL-адресу в адресной строке браузера
  2. Компонент – компонент, создаваемый при активном маршруте (навигация)

Если пользователь нажимает кнопку List Users , которая ссылается на путь /users , или вводит URL-адрес в адресной строке браузера, маршрутизатор отобразит файл шаблона UserListComponent компонента в заполнителе .

Аналогично, если они нажмут кнопку Добавить пользователя , он отобразит компонент UserForm .

3.11. Файл app.module.ts

Затем нам нужно отредактировать файл app.module.ts , чтобы Angular мог импортировать все необходимые модули, компоненты и службы.

Кроме того, нам нужно указать, какого поставщика мы будем использовать для создания и внедрения класса UserService . В противном случае Angular не сможет внедрить его в классы компонентов:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { UserListComponent } from './user-list/user-list.component';
import { UserFormComponent } from './user-form/user-form.component';
import { UserService } from './service/user.service';

@NgModule({
  declarations: [
    AppComponent,
    UserListComponent,
    UserFormComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    FormsModule
  ],
  providers: [UserService],
  bootstrap: [AppComponent]
})
export class AppModule { }

4. Запуск приложения

Наконец, мы готовы запустить наше приложение.

Для этого давайте сначала запустим приложение Spring Boot, чтобы служба REST была активна и прослушивала запросы.

После запуска приложения Spring Boot откройте консоль управления и введите следующую команду:

ng serve --open

Это запустит Angular live development server, а также откроет браузер по адресу http://localhost:4200 .

Мы должны увидеть панель навигации с кнопками для перечисления существующих объектов и добавления новых. Если мы нажмем первую кнопку, мы увидим под панелью навигации таблицу со списком сущностей, сохраненных в базе данных:
Аналогично, нажатие второй кнопки отобразит HTML-форму для сохранения новой сущности:

5. Заключение

В этом уроке мы узнали, как создать базовое веб-приложение с помощью Spring Boot и Angular .

Как обычно, все примеры кода, показанные в этом руководстве, доступны на GitHub .