kamyshov_danila_lab_3 is ready #90
154
kamyshov_danila_lab_3/README.md
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
# Лабораторная работа №3 - REST API, Gateway и синхронный обмен между микросервисами
|
||||||
|
|
||||||
|
Цель: изучение шаблона проектирования gateway, построения синхронного обмена между микросервисами и архитектурного стиля RESTful API.
|
||||||
|
|
||||||
|
Задачи:
|
||||||
|
|
||||||
|
Создать 2 микросервиса, реализующих CRUD на связанных сущностях.
|
||||||
|
Реализовать механизм синхронного обмена сообщениями между микросервисами.
|
||||||
|
Реализовать шлюз на основе прозрачного прокси-сервера nginx.
|
||||||
|
|
||||||
|
# Создание микросервисов
|
||||||
|
Первый микросервис - messaging-application для сущности "Приложение для обмена сообщениями"
|
||||||
|
Второй микросервис - user-device-application для сущности "Устройство пользователя"
|
||||||
|
|
||||||
|
Сущность: Устройство пользователя (User Device):
|
||||||
|
UUID (Уникальный идентификатор): Уникальный номер или код, идентифицирующий конкретное устройство пользователя.
|
||||||
|
Модель (Model): Название и модель устройства пользователя.
|
||||||
|
Тип интерфейса (Interface Type): Тип интерфейса для подключения к веб-приложению (Web, Mobile, Desktop и т.д.).
|
||||||
|
UUID приложения для обмена сообщениями (messagingAppUuid): Уникальный идентификатор приложения для обмена сообщениями, с которым данное устройство пользователя связано. Это поле устанавливает связь "1-ко-многим" между устройством и приложением.
|
||||||
|
|
||||||
|
Сущность: Приложение для обмена сообщениями (Messaging Application):
|
||||||
|
UUID (Уникальный идентификатор): Уникальный номер или код, идентифицирующий конкретное приложение для обмена сообщениями.
|
||||||
|
Название (Name): Название приложения для обмена сообщениями.
|
||||||
|
Поддерживаемые платформы (Supported Platforms): Операционные системы и устройства, на которых работает приложение (Web, Mobile, Desktop и др.).
|
||||||
|
Максимальное количество участников (Maximum Participants): Максимальное количество пользователей, которое может использовать приложение для обмена сообщениями одновременно.
|
||||||
|
|
||||||
|
Связь "1-ко-многим" между этими сущностями реализуется через поле "UUID приложения" в сущности "Устройство пользователя". Каждое устройство пользователя связано с конкретным приложением для обмена сообщениями через UUID этого приложения, что позволяет одному приложению быть связанным с несколькими устройствами.
|
||||||
|
|
||||||
|
Вот примеры моделей для запросов:
|
||||||
|
Пример модели "Приложение для обмена сообщениями" для списка:
|
||||||
|
{
|
||||||
|
"uuid": "8f036445-a5bd-401c-926e-840f9de795cd",
|
||||||
|
"Name": "Messenger",
|
||||||
|
"Supported Platforms": "Web, iOS, Android",
|
||||||
|
"Maximum Participants": 100
|
||||||
|
}
|
||||||
|
Пример модели "Приложение для обмена сообщениями" для создания или изменения:
|
||||||
|
{
|
||||||
|
"uuid": "8f036445-a5bd-401c-926e-840f9de795cd",
|
||||||
|
"Name": "Messenger",
|
||||||
|
"Supported Platforms": "Web, iOS, Android",
|
||||||
|
"Maximum Participants": 100
|
||||||
|
}
|
||||||
|
Пример модели "Устройство пользователя" для списка:
|
||||||
|
{
|
||||||
|
"uuid": "8740d660-b251-4272-8535-be7ec3748d4b",
|
||||||
|
"Model": "iPhone X",
|
||||||
|
"type": "Mobile",
|
||||||
|
"Interface Type": "ios",
|
||||||
|
"messagingAppUuid": "8f036445-a5bd-401c-926e-840f9de795cd"
|
||||||
|
}
|
||||||
|
|
||||||
|
Пример модели "Устройство пользователя" для создания или изменения:
|
||||||
|
{
|
||||||
|
"Model": "iPhone X",
|
||||||
|
"type": "Mobile",
|
||||||
|
"Interface Type": "ios",
|
||||||
|
"messagingAppUuid": "8f036445-a5bd-401c-926e-840f9de795cd"
|
||||||
|
}
|
||||||
|
Пример модели "Устройство пользователя" для подробностей:
|
||||||
|
{
|
||||||
|
"uuid": "8740d660-b251-4272-8535-be7ec3748d4b",
|
||||||
|
"Model": "iPhone X",
|
||||||
|
"type": "Mobile",
|
||||||
|
"Interface Type": "ios",
|
||||||
|
"messagingAppUuid": "8f036445-a5bd-401c-926e-840f9de795cd",
|
||||||
|
"messagingAppInfo": {
|
||||||
|
"Name": "Messenger",
|
||||||
|
"Supported Platforms": "Web, iOS, Android",
|
||||||
|
"Maximum Participants": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<div>Структура 1-го микросервиса</div>
|
||||||
|
<img src="screens/img1.png" width="650" title="Структура 1-го микросервиса">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<div>Структура 2-го микросервиса</div>
|
||||||
|
<img src="screens/img2.png" width="650" title="Структура 2-го микросервиса">
|
||||||
|
</p>
|
||||||
|
- контроллеры для обработка запросов, дтошки для выбора что изображать в сваггере при запросах, модели для сущностей, репозитории для отправки данных, сервисы для бизнес-логики
|
||||||
|
|
||||||
|
# Докер файлы, докер компоус, nginx
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<div>Докер файл для 1-го микросервиса</div>
|
||||||
|
<img src="screens/img3.png" width="650" title="Докер файл для 1-го микросервиса">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<div>Докер файл для 2-го микросервиса</div>
|
||||||
|
<img src="screens/img4.png" width="650" title="Докер файл для 2-го микросервиса">
|
||||||
|
</p>
|
||||||
|
-Использования базового образа, установка рабочий директории, копирования джар файла, экспорт порта, запуск приложения при запуске контейнера
|
||||||
|
<p>
|
||||||
|
<div>Докер компоус</div>
|
||||||
|
<img src="screens/img5.png" width="650" title="Докер компоус">
|
||||||
|
</p>
|
||||||
|
-создания общей сети для всех сервисов, запуск образов сервисов, проброска портов, копирования конфигурационного файла nginx и запуск этого сервиса после запуска других сервисов
|
||||||
|
<p>
|
||||||
|
<div>nginx</div>
|
||||||
|
<img src="screens/img6.png" width="650" title="nginx">
|
||||||
|
</p>
|
||||||
|
установка количества одновремменных подключений, прослушка запросов по 80 порту, серверное имя локалхост, адрес для переадресации запросов по нему, url переадрусации
|
||||||
|
<p>
|
||||||
|
<div>Скрин созданых образов</div>
|
||||||
|
<img src="screens/img7.png" width="650" title="Скрин созданых образов">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<div>Скрин созданых контейнеров</div>
|
||||||
|
<img src="screens/img8.png" width="650" title="Скрин созданых контейнеров">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<div>Swagger 1-го микросервиса</div>
|
||||||
|
<img src="screens/img9.png" width="650" title="Swagger 1-го микросервиса">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<img src="screens/img10.png" width="650">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<img src="screens/img11.png" width="650">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<img src="screens/img12.png" width="650">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<img src="screens/img13.png" width="650">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<img src="screens/img14.png" width="650">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<div>Swagger 2-го микросервиса</div>
|
||||||
|
<img src="screens/img15.png" width="650" title="Swagger 2-го микросервиса">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<img src="screens/img16.png" width="650">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<img src="screens/img17.png" width="650">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<img src="screens/img18.png" width="650">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<img src="screens/img19.png" width="650">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<img src="screens/img20.png" width="650">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
# Видео
|
||||||
|
|
||||||
|
Видео с разбором лабораторной работы - https://drive.google.com/file/d/1hOHcZAP8aECQXtKm1CcHNDtKli1TdJLO/view?usp=sharing
|
@ -0,0 +1,14 @@
|
|||||||
|
# Используем базовый образ с Java и средой выполнения Spring Boot
|
||||||
|
FROM openjdk:17-jdk-slim
|
||||||
|
|
||||||
|
# Устанавливаем рабочий каталог внутри контейнера
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Копируем JAR-файл приложения в контейнер (предполагается, что JAR-файл находится в каталоге target/)
|
||||||
|
COPY target/messaging-application-0.0.1-SNAPSHOT.jar messaging-application.jar
|
||||||
|
|
||||||
|
# Экспонируем порт, на котором будет работать приложение
|
||||||
|
EXPOSE 8099
|
||||||
|
|
||||||
|
# Запускаем приложение при запуске контейнера
|
||||||
|
CMD ["java", "-jar", "messaging-application.jar"]
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.example.messagingapplication;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class MessagingApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(MessagingApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
package com.example.messagingapplication.controller;
|
||||||
|
|
||||||
|
import com.example.messagingapplication.model.MessagingApplication;
|
||||||
|
import com.example.messagingapplication.dto.MessagingApplicationDTO;
|
||||||
|
import com.example.messagingapplication.service.MessagingApplicationService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/messaging-application")
|
||||||
|
public class MessagingApplicationController {
|
||||||
|
private final MessagingApplicationService applicationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public MessagingApplicationController(MessagingApplicationService applicationService) {
|
||||||
|
this.applicationService = applicationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/")
|
||||||
|
public List<MessagingApplication> getAllApplications() {
|
||||||
|
return applicationService.getAllApplications();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{uuid}")
|
||||||
|
public ResponseEntity<MessagingApplication> getApplicationByUuid(@PathVariable String uuid) {
|
||||||
|
return applicationService.getApplicationByUuid(uuid)
|
||||||
|
.map(app -> ResponseEntity.ok().body(app))
|
||||||
|
.orElse(ResponseEntity.notFound().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/")
|
||||||
|
public ResponseEntity<MessagingApplication> createApplication(@RequestBody MessagingApplicationDTO applicationDTO) {
|
||||||
|
MessagingApplication createdApplication = applicationService.createApplication(applicationDTO);
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(createdApplication);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{uuid}")
|
||||||
|
public ResponseEntity<MessagingApplication> updateApplication(@PathVariable String uuid, @RequestBody MessagingApplicationDTO applicationDTO) {
|
||||||
|
MessagingApplication updatedApplication = applicationService.updateApplication(uuid, applicationDTO);
|
||||||
|
if (updatedApplication != null) {
|
||||||
|
return ResponseEntity.ok().body(updatedApplication);
|
||||||
|
} else {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{uuid}")
|
||||||
|
public ResponseEntity<Void> deleteApplication(@PathVariable String uuid) {
|
||||||
|
boolean deleted = applicationService.deleteApplication(uuid);
|
||||||
|
return deleted ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.example.messagingapplication.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class MessagingApplicationDTO {
|
||||||
|
private String name;
|
||||||
|
private String supportedPlatforms;
|
||||||
|
private int maximumParticipants;
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.example.messagingapplication.model;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "messaging_application")
|
||||||
|
@Data
|
||||||
|
public class MessagingApplication {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
private String uuid;
|
||||||
|
private String name;
|
||||||
|
private String supportedPlatforms;
|
||||||
|
private int maximumParticipants;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.example.messagingapplication.repository;
|
||||||
|
|
||||||
|
import com.example.messagingapplication.model.MessagingApplication;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface MessagingApplicationRepository extends JpaRepository<MessagingApplication, Long> {
|
||||||
|
Optional<MessagingApplication> findByUuid(String uuid);
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package com.example.messagingapplication.service;
|
||||||
|
|
||||||
|
import com.example.messagingapplication.model.MessagingApplication;
|
||||||
|
import com.example.messagingapplication.dto.MessagingApplicationDTO;
|
||||||
|
import com.example.messagingapplication.repository.MessagingApplicationRepository;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MessagingApplicationService {
|
||||||
|
private final MessagingApplicationRepository applicationRepository;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public List<MessagingApplication> getAllApplications() {
|
||||||
|
return applicationRepository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Optional<MessagingApplication> getApplicationByUuid(String uuid) {
|
||||||
|
return applicationRepository.findByUuid(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public MessagingApplication createApplication(MessagingApplicationDTO applicationDTO) {
|
||||||
|
MessagingApplication application = new MessagingApplication();
|
||||||
|
application.setUuid(createUUID());
|
||||||
|
application.setName(applicationDTO.getName());
|
||||||
|
application.setSupportedPlatforms(applicationDTO.getSupportedPlatforms());
|
||||||
|
application.setMaximumParticipants(applicationDTO.getMaximumParticipants());
|
||||||
|
return applicationRepository.save(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public MessagingApplication updateApplication(String uuid, MessagingApplicationDTO applicationDTO) {
|
||||||
|
Optional<MessagingApplication> existingApplication = applicationRepository.findByUuid(uuid);
|
||||||
|
if (existingApplication.isPresent()) {
|
||||||
|
MessagingApplication application = existingApplication.get();
|
||||||
|
application.setName(applicationDTO.getName());
|
||||||
|
application.setSupportedPlatforms(applicationDTO.getSupportedPlatforms());
|
||||||
|
application.setMaximumParticipants(applicationDTO.getMaximumParticipants());
|
||||||
|
return applicationRepository.save(application);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public boolean deleteApplication(String uuid) {
|
||||||
|
Optional<MessagingApplication> existingApplication = applicationRepository.findByUuid(uuid);
|
||||||
|
if (existingApplication.isPresent()) {
|
||||||
|
applicationRepository.delete(existingApplication.get());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createUUID() {
|
||||||
|
Random random = new Random();
|
||||||
|
long mostSigBits = random.nextLong();
|
||||||
|
long leastSigBits = random.nextLong();
|
||||||
|
return String.format("%08x-%04x-%04x-%04x-%012x",
|
||||||
|
mostSigBits >>> 32, (mostSigBits >>> 16) & 0xFFFF, mostSigBits & 0xFFFF,
|
||||||
|
(leastSigBits >>> 16) & 0xFFFF, leastSigBits & 0xFFFF);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
spring.datasource.url=jdbc:h2:mem:testdb
|
||||||
|
spring.datasource.driverClassName=org.h2.Driver
|
||||||
|
spring.datasource.username=sa
|
||||||
|
spring.datasource.password=password
|
||||||
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
|
spring.h2.console.enabled=true
|
||||||
|
|
||||||
|
server.port=8099
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.example.messagingapplication;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class MessagingApplicationApplicationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
BIN
kamyshov_danila_lab_3/screens/img1.png
Normal file
After Width: | Height: | Size: 69 KiB |
BIN
kamyshov_danila_lab_3/screens/img10.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
kamyshov_danila_lab_3/screens/img11.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
kamyshov_danila_lab_3/screens/img12.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
kamyshov_danila_lab_3/screens/img13.png
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
kamyshov_danila_lab_3/screens/img14.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
kamyshov_danila_lab_3/screens/img15.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
kamyshov_danila_lab_3/screens/img16.png
Normal file
After Width: | Height: | Size: 61 KiB |
BIN
kamyshov_danila_lab_3/screens/img17.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
kamyshov_danila_lab_3/screens/img18.png
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
kamyshov_danila_lab_3/screens/img19.png
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
kamyshov_danila_lab_3/screens/img2.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
kamyshov_danila_lab_3/screens/img20.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
kamyshov_danila_lab_3/screens/img3.png
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
kamyshov_danila_lab_3/screens/img4.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
kamyshov_danila_lab_3/screens/img5.png
Normal file
After Width: | Height: | Size: 77 KiB |
BIN
kamyshov_danila_lab_3/screens/img6.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
kamyshov_danila_lab_3/screens/img7.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
kamyshov_danila_lab_3/screens/img8.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
kamyshov_danila_lab_3/screens/img9.png
Normal file
After Width: | Height: | Size: 55 KiB |
@ -0,0 +1,14 @@
|
|||||||
|
# Используем базовый образ с Java и средой выполнения Spring Boot
|
||||||
|
FROM openjdk:17-jdk-slim
|
||||||
|
|
||||||
|
# Устанавливаем рабочий каталог внутри контейнера
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Копируем JAR-файл приложения в контейнер (предполагается, что JAR-файл находится в каталоге target/)
|
||||||
|
COPY target/user-device-application-0.0.1-SNAPSHOT.jar user-device-application.jar
|
||||||
|
|
||||||
|
# Экспонируем порт, на котором будет работать приложение
|
||||||
|
EXPOSE 8090
|
||||||
|
|
||||||
|
# Запускаем приложение при запуске контейнера
|
||||||
|
CMD ["java", "-jar", "user-device-application.jar"]
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.example.userdeviceapplication;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class UserDeviceApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(UserDeviceApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RestTemplate restTemplate() {
|
||||||
|
return new RestTemplate();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package com.example.userdeviceapplication.controller;
|
||||||
|
|
||||||
|
import com.example.userdeviceapplication.dto.UserDeviceCreateUpdateDTO;
|
||||||
|
import com.example.userdeviceapplication.dto.UserDeviceDTO;
|
||||||
|
import com.example.userdeviceapplication.dto.UserDeviceDetailDTO;
|
||||||
|
import com.example.userdeviceapplication.service.UserDeviceService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/user-device-application")
|
||||||
|
public class UserDeviceController {
|
||||||
|
private final UserDeviceService userDeviceService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public UserDeviceController(UserDeviceService userDeviceService) {
|
||||||
|
this.userDeviceService = userDeviceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/")
|
||||||
|
public ResponseEntity<List<UserDeviceDTO>> getUserDevices() {
|
||||||
|
List<UserDeviceDTO> userDevices = userDeviceService.getAllUserDevices();
|
||||||
|
return ResponseEntity.ok(userDevices);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{uuid}")
|
||||||
|
public ResponseEntity<UserDeviceDetailDTO> getUserDevice(@PathVariable String uuid) {
|
||||||
|
UserDeviceDetailDTO userDevice = userDeviceService.getUserDeviceByUuid(uuid);
|
||||||
|
if (userDevice != null) {
|
||||||
|
return ResponseEntity.ok(userDevice);
|
||||||
|
}
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/")
|
||||||
|
public ResponseEntity<UserDeviceDetailDTO> createUserDevice(@RequestBody UserDeviceCreateUpdateDTO createDTO) {
|
||||||
|
UserDeviceDetailDTO userDevice = userDeviceService.createUserDevice(createDTO);
|
||||||
|
return ResponseEntity.ok(userDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{uuid}")
|
||||||
|
public ResponseEntity<UserDeviceDetailDTO> updateUserDevice(@PathVariable String uuid, @RequestBody UserDeviceCreateUpdateDTO updateDTO) {
|
||||||
|
UserDeviceDetailDTO userDevice = userDeviceService.updateUserDevice(uuid, updateDTO);
|
||||||
|
if (userDevice != null) {
|
||||||
|
return ResponseEntity.ok(userDevice);
|
||||||
|
}
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{uuid}")
|
||||||
|
public ResponseEntity<Void> deleteUserDevice(@PathVariable String uuid) {
|
||||||
|
boolean deleted = userDeviceService.deleteUserDevice(uuid);
|
||||||
|
if (deleted) {
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
messaging-application:
|
||||||
|
image: messagingapplication_microservice_1:1.0
|
||||||
|
ports:
|
||||||
|
- "8099:8099"
|
||||||
|
networks:
|
||||||
|
- network
|
||||||
|
|
||||||
|
user-device-application:
|
||||||
|
image: userdeviceapplication_microservice_2:1.0
|
||||||
|
ports:
|
||||||
|
- "8090:8090"
|
||||||
|
networks:
|
||||||
|
- network
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:latest
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
networks:
|
||||||
|
- network
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
depends_on:
|
||||||
|
- messaging-application
|
||||||
|
- user-device-application
|
||||||
|
|
||||||
|
networks:
|
||||||
|
network:
|
||||||
|
driver: bridge
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.example.userdeviceapplication.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UserDeviceCreateUpdateDTO {
|
||||||
|
private String model;
|
||||||
|
private String type;
|
||||||
|
private String interfaceType;
|
||||||
|
private String messagingAppUuid;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.example.userdeviceapplication.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UserDeviceDTO {
|
||||||
|
private String uuid;
|
||||||
|
private String model;
|
||||||
|
private String type;
|
||||||
|
private String interfaceType;
|
||||||
|
private String messagingAppUuid;
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.example.userdeviceapplication.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UserDeviceDetailDTO {
|
||||||
|
private String uuid;
|
||||||
|
private String model;
|
||||||
|
private String type;
|
||||||
|
private String interfaceType;
|
||||||
|
private String messagingAppUuid;
|
||||||
|
private UserDeviceDetailInfoDTO messagingAppInfo;
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.example.userdeviceapplication.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UserDeviceDetailInfoDTO {
|
||||||
|
private String name;
|
||||||
|
private String supportedPlatforms;
|
||||||
|
private int maximumParticipants;
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.example.userdeviceapplication.model;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Data
|
||||||
|
public class UserDevice {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
private String uuid;
|
||||||
|
private String model;
|
||||||
|
private String type;
|
||||||
|
private String interfaceType;
|
||||||
|
private String messagingAppUuid;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
location /messaging-application/ {
|
||||||
|
proxy_pass http://messaging-application:8099;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /user-device-application/ {
|
||||||
|
proxy_pass http://user-device-application:8090;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.example.userdeviceapplication.repository;
|
||||||
|
|
||||||
|
import com.example.userdeviceapplication.model.UserDevice;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface UserDeviceRepository extends JpaRepository<UserDevice, Long> {
|
||||||
|
UserDevice findByUuid(String uuid);
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
package com.example.userdeviceapplication.service;
|
||||||
|
|
||||||
|
import com.example.userdeviceapplication.dto.UserDeviceCreateUpdateDTO;
|
||||||
|
import com.example.userdeviceapplication.dto.UserDeviceDTO;
|
||||||
|
import com.example.userdeviceapplication.dto.UserDeviceDetailDTO;
|
||||||
|
import com.example.userdeviceapplication.dto.UserDeviceDetailInfoDTO;
|
||||||
|
import com.example.userdeviceapplication.model.UserDevice;
|
||||||
|
import com.example.userdeviceapplication.repository.UserDeviceRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class UserDeviceService {
|
||||||
|
private final UserDeviceRepository userDeviceRepository;
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public UserDeviceService(UserDeviceRepository userDeviceRepository, RestTemplate restTemplate) {
|
||||||
|
this.userDeviceRepository = userDeviceRepository;
|
||||||
|
this.restTemplate = restTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<UserDeviceDTO> getAllUserDevices() {
|
||||||
|
List<UserDevice> userDevices = userDeviceRepository.findAll();
|
||||||
|
return userDevices.stream()
|
||||||
|
.map(this::convertToUserDeviceDTO)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserDeviceDetailDTO getUserDeviceByUuid(String uuid) {
|
||||||
|
UserDevice userDevice = userDeviceRepository.findByUuid(uuid);
|
||||||
|
if (userDevice != null) {
|
||||||
|
return convertToUserDeviceDetailDTO(userDevice);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserDeviceDetailDTO createUserDevice(UserDeviceCreateUpdateDTO createDTO) {
|
||||||
|
UserDevice userDevice = new UserDevice();
|
||||||
|
userDevice.setUuid(createUUID());
|
||||||
|
updateUserDeviceFromDTO(userDevice, createDTO);
|
||||||
|
userDevice = userDeviceRepository.save(userDevice);
|
||||||
|
return convertToUserDeviceDetailDTO(userDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserDeviceDetailDTO updateUserDevice(String uuid, UserDeviceCreateUpdateDTO updateDTO) {
|
||||||
|
UserDevice userDevice = userDeviceRepository.findByUuid(uuid);
|
||||||
|
if (userDevice != null) {
|
||||||
|
updateUserDeviceFromDTO(userDevice, updateDTO);
|
||||||
|
userDevice = userDeviceRepository.save(userDevice);
|
||||||
|
return convertToUserDeviceDetailDTO(userDevice);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deleteUserDevice(String uuid) {
|
||||||
|
UserDevice userDevice = userDeviceRepository.findByUuid(uuid);
|
||||||
|
if (userDevice != null) {
|
||||||
|
userDeviceRepository.delete(userDevice);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserDeviceDTO convertToUserDeviceDTO(UserDevice userDevice) {
|
||||||
|
UserDeviceDTO dto = new UserDeviceDTO();
|
||||||
|
dto.setUuid(userDevice.getUuid());
|
||||||
|
dto.setModel(userDevice.getModel());
|
||||||
|
dto.setType(userDevice.getType());
|
||||||
|
dto.setInterfaceType(userDevice.getInterfaceType());
|
||||||
|
dto.setMessagingAppUuid(userDevice.getMessagingAppUuid());
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserDeviceDetailDTO convertToUserDeviceDetailDTO(UserDevice userDevice) {
|
||||||
|
UserDeviceDetailDTO detailDTO = new UserDeviceDetailDTO();
|
||||||
|
detailDTO.setUuid(userDevice.getUuid());
|
||||||
|
detailDTO.setModel(userDevice.getModel());
|
||||||
|
detailDTO.setType(userDevice.getType());
|
||||||
|
detailDTO.setInterfaceType(userDevice.getInterfaceType());
|
||||||
|
detailDTO.setMessagingAppUuid(userDevice.getMessagingAppUuid());
|
||||||
|
|
||||||
|
UserDeviceDetailInfoDTO subscriptionInfo = getmessagingAppInfo(userDevice.getMessagingAppUuid());
|
||||||
|
detailDTO.setMessagingAppInfo(subscriptionInfo);
|
||||||
|
|
||||||
|
return detailDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateUserDeviceFromDTO(UserDevice userDevice, UserDeviceCreateUpdateDTO dto) {
|
||||||
|
userDevice.setModel(dto.getModel());
|
||||||
|
userDevice.setType(dto.getType());
|
||||||
|
userDevice.setInterfaceType(dto.getInterfaceType());
|
||||||
|
userDevice.setMessagingAppUuid(dto.getMessagingAppUuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createUUID() {
|
||||||
|
Random random = new Random();
|
||||||
|
long mostSigBits = random.nextLong();
|
||||||
|
long leastSigBits = random.nextLong();
|
||||||
|
return String.format("%08x-%04x-%04x-%04x-%012x",
|
||||||
|
mostSigBits >>> 32, (mostSigBits >>> 16) & 0xFFFF, mostSigBits & 0xFFFF,
|
||||||
|
(leastSigBits >>> 16) & 0xFFFF, leastSigBits & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserDeviceDetailInfoDTO getmessagingAppInfo(String messagingAppUuid) {
|
||||||
|
String messagingAppInfoUrl = "http://nginx/messaging-application/" + messagingAppUuid;
|
||||||
|
return restTemplate.getForObject(messagingAppInfoUrl, UserDeviceDetailInfoDTO.class);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
spring.datasource.url=jdbc:h2:mem:testdb
|
||||||
|
spring.datasource.driverClassName=org.h2.Driver
|
||||||
|
spring.datasource.username=sa
|
||||||
|
spring.datasource.password=password
|
||||||
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
|
spring.h2.console.enabled=true
|
||||||
|
|
||||||
|
server.port=8090
|
||||||
|
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.example.userdeviceapplication;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class UserDeviceApplicationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|