shadaev_anton_lab_3 #76
74
shadaev_anton_lab_3/README.md
Normal file
@ -0,0 +1,74 @@
|
||||
# Лабораторная работа №3 - REST API, Gateway и синхронный обмен между микросервисами
|
||||
Цель:
|
||||
|
||||
Изучение шаблона проектирования gateway, построения синхронного обмена между микросервисами и архитектурного стиля RESTful API.
|
||||
|
||||
Задачи:
|
||||
|
||||
Создать 2 микросервиса, реализующих CRUD на связанных сущностях. Реализовать механизм синхронного обмена сообщениями между микросервисами. Реализовать шлюз на основе прозрачного прокси-сервера nginx.
|
||||
|
||||
## Запуск:
|
||||
|
||||
Чтобы запустить контейнеры в docker, необходимо выполнить следующую команду: `docker-compose -f \ docker-compose.yml up -d`, где:
|
||||
|
||||
-f - путь до docker-compose.yml файла
|
||||
-d - фоновый режим запуска
|
||||
|
||||
|
||||
## Демонстрация работы программы
|
||||
### Сервис Aggregator
|
||||
<u>POST-метод для создания вакансии</u>
|
||||
|
||||
![1.png](screenshots%2F1.png)
|
||||
|
||||
<u>GET-метод для получения вакансии по id</u>
|
||||
|
||||
![2.png](screenshots%2F2.png)
|
||||
|
||||
<u>GET-метод для получения списка вакансий</u>
|
||||
|
||||
![3.png](screenshots%2F3.png)
|
||||
|
||||
<u>PUT-метод для обновления вакансии</u>
|
||||
|
||||
![4.png](screenshots%2F4.png)
|
||||
|
||||
<u>DELETE-метод для удаления вакансии</u>
|
||||
|
||||
![5.png](screenshots%2F5.png)
|
||||
|
||||
### Метод, связывающий оба микросервиса
|
||||
<u>Демонстрация работы:</u>
|
||||
|
||||
![img_12.png](screenshots%2Fimg_12.png)
|
||||
|
||||
### Сущности
|
||||
Page -> Jobs (One-to-Many)
|
||||
|
||||
![img.png](screenshots/test/img.png)
|
||||
|
||||
![img_1.png](screenshots/test/img_1.png)
|
||||
|
||||
### Dockerfile (aggregator-api)
|
||||
|
||||
![img_2.png](screenshots/test/img_2.png)
|
||||
|
||||
### Dockerfile (parser-api)
|
||||
|
||||
![img_3.png](screenshots/test/img_3.png)
|
||||
|
||||
### Docker compose
|
||||
|
||||
![img_4.png](screenshots/test/img_4.png)
|
||||
|
||||
![img_5.png](screenshots/test/img_5.png)
|
||||
|
||||
![img_6.png](screenshots/test/img_6.png)
|
||||
|
||||
![img_7.png](screenshots/test/img_7.png)
|
||||
|
||||
### Nginx
|
||||
![img_8.png](screenshots%2Ftest%2Fimg_8.png)
|
||||
|
||||
## Ссылка на видео:
|
||||
https://youtu.be/oPLQxyRDlXw
|
9
shadaev_anton_lab_3/aggregator-api/Dockerfile
Normal file
@ -0,0 +1,9 @@
|
||||
FROM openjdk:17-jdk-slim
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY aggregator-api-1.0-SNAPSHOT.jar /app
|
||||
|
||||
CMD ["java", "-jar", "/app/aggregator-api-1.0-SNAPSHOT.jar"]
|
58
shadaev_anton_lab_3/aggregator-api/pom.xml
Normal file
@ -0,0 +1,58 @@
|
||||
<?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>
|
||||
<parent>
|
||||
<groupId>com.company</groupId>
|
||||
<artifactId>shadaev_anton_lab_3</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>aggregator-api</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>42.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,11 @@
|
||||
package com.company;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class AggregatorApiApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AggregatorApiApplication.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.company.controller;
|
||||
|
||||
import com.company.dto.JobDto;
|
||||
import com.company.exceptions.JobAlreadyExistsException;
|
||||
import com.company.exceptions.JobNotFoundException;
|
||||
import com.company.model.Job;
|
||||
import com.company.service.JobService;
|
||||
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;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/jobs")
|
||||
public class JobController {
|
||||
private final JobService jobService;
|
||||
|
||||
@Autowired
|
||||
public JobController(JobService jobService) {
|
||||
this.jobService = jobService;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<?> save(@RequestBody JobDto jobDto) {
|
||||
Job job;
|
||||
try {
|
||||
if (jobService.findJobByTitle(jobDto.getTitle()).isPresent())
|
||||
throw new JobAlreadyExistsException("Job already exists!");
|
||||
job = jobService.save(jobDto);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(job);
|
||||
} catch (JobAlreadyExistsException e) {
|
||||
return ResponseEntity.badRequest().body(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<Job> findAll() {
|
||||
return jobService.findAll();
|
||||
}
|
||||
|
||||
@GetMapping("/{uuid}")
|
||||
public ResponseEntity<Job> findJobByUUID(@PathVariable UUID uuid) {
|
||||
return jobService.findJobByUUID(uuid)
|
||||
.map(app -> ResponseEntity.ok().body(app))
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
@PutMapping("/{uuid}")
|
||||
public ResponseEntity<?> updateJobByUUID(@PathVariable UUID uuid, @RequestBody JobDto jobDto) {
|
||||
Job job;
|
||||
try {
|
||||
if (jobService.findJobByUUID(uuid).isEmpty())
|
||||
throw new JobNotFoundException("Job not found!");
|
||||
job = jobService.updateJobByUUID(uuid, jobDto);
|
||||
return ResponseEntity.ok().body(job);
|
||||
} catch (JobNotFoundException e) {
|
||||
return ResponseEntity.badRequest().body(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/{uuid}")
|
||||
public ResponseEntity<?> deleteJobByUUID(@PathVariable UUID uuid) {
|
||||
UUID statusId;
|
||||
try {
|
||||
if (!jobService.findJobByUUID(uuid).isPresent())
|
||||
throw new JobNotFoundException("Job not found!");
|
||||
statusId = jobService.deleteJobByUUID(uuid);
|
||||
return ResponseEntity.ok().body(statusId);
|
||||
} catch (JobNotFoundException e) {
|
||||
return ResponseEntity.badRequest().body(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.company.dto;
|
||||
|
||||
import com.company.model.Job;
|
||||
import lombok.Getter;
|
||||
|
||||
public record JobDto(@Getter String title, @Getter String description) {
|
||||
|
||||
public JobDto(String title, String description) {
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public static Job toJob(JobDto jobDto) {
|
||||
return Job.builder()
|
||||
.title(jobDto.getTitle())
|
||||
.description(jobDto.getDescription())
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.company.exceptions;
|
||||
|
||||
public class JobAlreadyExistsException extends Exception {
|
||||
public JobAlreadyExistsException() {
|
||||
}
|
||||
|
||||
public JobAlreadyExistsException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.company.exceptions;
|
||||
|
||||
public class JobNotFoundException extends Exception {
|
||||
public JobNotFoundException() {
|
||||
}
|
||||
|
||||
public JobNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.company.model;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "jobs")
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class Job {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private UUID id;
|
||||
private String title;
|
||||
private String description;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.company.repo;
|
||||
|
||||
import com.company.model.Job;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface JobRepository extends JpaRepository<Job, UUID> {
|
||||
Optional<Job> findJobByTitle(String title);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.company.service;
|
||||
|
||||
import com.company.dto.JobDto;
|
||||
import com.company.model.Job;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface JobService {
|
||||
Job save(JobDto job);
|
||||
List<Job> findAll();
|
||||
Optional<Job> findJobByUUID(UUID uuid);
|
||||
Optional<Job> findJobByTitle(String title);
|
||||
Job updateJobByUUID(UUID uuid, JobDto jobDto);
|
||||
UUID deleteJobByUUID(UUID uuid);
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.company.service.impl;
|
||||
|
||||
import com.company.dto.JobDto;
|
||||
import com.company.model.Job;
|
||||
import com.company.repo.JobRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class JobService implements com.company.service.JobService {
|
||||
private final JobRepository jobRepository;
|
||||
|
||||
@Autowired
|
||||
public JobService(JobRepository jobRepository) {
|
||||
this.jobRepository = jobRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Job save(JobDto jobDto) {
|
||||
return jobRepository.save(JobDto.toJob(jobDto));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public List<Job> findAll(){
|
||||
return jobRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Optional<Job> findJobByUUID(UUID uuid) {
|
||||
return Optional.ofNullable(jobRepository.findById(uuid).get());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Optional<Job> findJobByTitle(String title) {
|
||||
return Optional.ofNullable(jobRepository.findJobByTitle(title)).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Job updateJobByUUID(UUID uuid, JobDto jobDto) {
|
||||
Job job = jobRepository.findById(uuid).get();
|
||||
job.setTitle(jobDto.getTitle());
|
||||
job.setDescription(jobDto.getDescription());
|
||||
return jobRepository.save(job);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public UUID deleteJobByUUID(UUID uuid) {
|
||||
jobRepository.deleteById(uuid);
|
||||
return uuid;
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
spring:
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
show-sql: true
|
||||
datasource:
|
||||
driverClassName: org.postgresql.Driver
|
||||
url: jdbc:postgresql://localhost:5433/aggregator_db
|
||||
username: postgres
|
||||
password: postgres
|
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>test</title>
|
||||
</head>
|
||||
<body>
|
||||
test...
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,13 @@
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
spring:
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
show-sql: true
|
||||
datasource:
|
||||
driverClassName: org.postgresql.Driver
|
||||
url: jdbc:postgresql://localhost:5433/aggregator_db
|
||||
username: postgres
|
||||
password: postgres
|
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>test</title>
|
||||
</head>
|
||||
<body>
|
||||
test...
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,3 @@
|
||||
artifactId=aggregator-api
|
||||
groupId=com.company
|
||||
version=1.0-SNAPSHOT
|
@ -0,0 +1,10 @@
|
||||
com/company/controller/JobController.class
|
||||
com/company/service/JobService.class
|
||||
com/company/model/Job$JobBuilder.class
|
||||
com/company/exceptions/JobAlreadyExistsException.class
|
||||
com/company/exceptions/JobNotFoundException.class
|
||||
com/company/repo/JobRepository.class
|
||||
com/company/dto/JobDto.class
|
||||
com/company/service/impl/JobService.class
|
||||
com/company/model/Job.class
|
||||
com/company/AggregatorApiApplication.class
|
@ -0,0 +1,9 @@
|
||||
/Users/a-shdv/IdeaProjects/aggregator/aggregator-api/src/main/java/com/company/dto/JobDto.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/aggregator-api/src/main/java/com/company/model/Job.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/aggregator-api/src/main/java/com/company/service/JobService.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/aggregator-api/src/main/java/com/company/exceptions/JobNotFoundException.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/aggregator-api/src/main/java/com/company/exceptions/JobAlreadyExistsException.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/aggregator-api/src/main/java/com/company/repo/JobRepository.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/aggregator-api/src/main/java/com/company/service/impl/JobService.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/aggregator-api/src/main/java/com/company/AggregatorApiApplication.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/aggregator-api/src/main/java/com/company/controller/JobController.java
|
74
shadaev_anton_lab_3/docker-compose.yaml
Normal file
@ -0,0 +1,74 @@
|
||||
version: '3.8'
|
||||
services:
|
||||
aggregator-api-service:
|
||||
# image: kybernetique/aggregator-api:latest
|
||||
build:
|
||||
context: ./aggregator-api
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8081:8080"
|
||||
environment:
|
||||
- SPRING_DATASOURCE_URL=jdbc:postgresql://postgres-service/aggregator_db
|
||||
- SPRING_DATASOURCE_USERNAME=postgres
|
||||
- SPRING_DATASOURCE_PASSWORD=postgres
|
||||
- SPRING_JPA_HIBERNATE_DDL_AUTO=create-drop
|
||||
depends_on:
|
||||
- postgres-service
|
||||
networks:
|
||||
backend:
|
||||
aliases:
|
||||
- "aggregator"
|
||||
|
||||
|
||||
parser-api-service:
|
||||
# image: kybernetique/parser-api:latest
|
||||
build:
|
||||
context: ./parser-api
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8082:8081"
|
||||
environment:
|
||||
- SPRING_DATASOURCE_URL=jdbc:postgresql://postgres-service/aggregator_db
|
||||
- SPRING_DATASOURCE_USERNAME=postgres
|
||||
- SPRING_DATASOURCE_PASSWORD=postgres
|
||||
- SPRING_JPA_HIBERNATE_DDL_AUTO=create-drop
|
||||
depends_on:
|
||||
- postgres-service
|
||||
networks:
|
||||
backend:
|
||||
aliases:
|
||||
- "parser"
|
||||
|
||||
postgres-service:
|
||||
image: postgres:14.1
|
||||
container_name: postgres-db
|
||||
restart: always
|
||||
ports:
|
||||
- "5433:5432"
|
||||
environment:
|
||||
POSTGRES_DB: "aggregator_db"
|
||||
POSTGRES_USER: "postgres"
|
||||
POSTGRES_PASSWORD: "postgres"
|
||||
networks:
|
||||
backend:
|
||||
aliases:
|
||||
- "postgres"
|
||||
|
||||
nginx-service:
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- "81:80"
|
||||
networks:
|
||||
backend:
|
||||
aliases:
|
||||
- "nginx"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||
depends_on:
|
||||
- aggregator-api-service
|
||||
- parser-api-service
|
||||
- postgres-service
|
||||
|
||||
networks:
|
||||
backend:
|
||||
driver: bridge
|
19
shadaev_anton_lab_3/nginx.conf
Normal file
@ -0,0 +1,19 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name localhost;
|
||||
|
||||
location /aggregator-api/ {
|
||||
proxy_pass http://aggregator-api-service:8080/;
|
||||
}
|
||||
|
||||
location /parser-api/ {
|
||||
proxy_pass http://parser-api-service:8081/;
|
||||
}
|
||||
}
|
||||
}
|
9
shadaev_anton_lab_3/parser-api/Dockerfile
Normal file
@ -0,0 +1,9 @@
|
||||
FROM openjdk:17-jdk-slim
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY parser-api-1.0-SNAPSHOT.jar /app
|
||||
|
||||
CMD ["java", "-jar", "/app/parser-api-1.0-SNAPSHOT.jar"]
|
BIN
shadaev_anton_lab_3/parser-api/parser-api-1.0-SNAPSHOT.jar
Normal file
58
shadaev_anton_lab_3/parser-api/pom.xml
Normal file
@ -0,0 +1,58 @@
|
||||
<?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>
|
||||
<parent>
|
||||
<groupId>com.company</groupId>
|
||||
<artifactId>shadaev_anton_lab_3</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>parser-api</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>42.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,18 @@
|
||||
package com.company;
|
||||
|
||||
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 ParserApiApplication {
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ParserApiApplication.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package com.company.controller;
|
||||
|
||||
import com.company.dto.PageDto;
|
||||
import com.company.exception.PageNotFoundException;
|
||||
import com.company.model.Page;
|
||||
import com.company.service.PageService;
|
||||
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;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/pages")
|
||||
public class PageController {
|
||||
private final PageService pageService;
|
||||
|
||||
@Autowired
|
||||
public PageController(PageService pageService) {
|
||||
this.pageService = pageService;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<?> save(@RequestBody PageDto pageDto) {
|
||||
Page page;
|
||||
page = pageService.save(pageDto);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(page);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<Page> findAll() {
|
||||
return pageService.findAll();
|
||||
}
|
||||
|
||||
@GetMapping("/{uuid}")
|
||||
public ResponseEntity<Page> findPageByUUID(@PathVariable UUID uuid) {
|
||||
return pageService.findPageByUUID(uuid)
|
||||
.map(app -> ResponseEntity.ok().body(app))
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
@PutMapping("/{uuid}")
|
||||
public ResponseEntity<?> updatePageByUUID(@PathVariable UUID uuid, @RequestBody PageDto pageDto) {
|
||||
Page page;
|
||||
try {
|
||||
if (pageService.findPageByUUID(uuid).isEmpty())
|
||||
throw new PageNotFoundException("Page not found!");
|
||||
page = pageService.updatePageByUUID(uuid, pageDto);
|
||||
return ResponseEntity.ok().body(page);
|
||||
} catch (PageNotFoundException e) {
|
||||
return ResponseEntity.badRequest().body(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/{uuid}")
|
||||
public ResponseEntity<?> deletePageByUUID(@PathVariable UUID uuid) {
|
||||
UUID statusId;
|
||||
try {
|
||||
if (!pageService.findPageByUUID(uuid).isPresent())
|
||||
throw new PageNotFoundException("Page not found!");
|
||||
statusId = pageService.deletePageByUUID(uuid);
|
||||
return ResponseEntity.ok().body(statusId);
|
||||
} catch (PageNotFoundException e) {
|
||||
return ResponseEntity.badRequest().body(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/find-job-info/{uuid}")
|
||||
public ResponseEntity<?> findJobInfo(@PathVariable UUID uuid) {
|
||||
return ResponseEntity.ok().body(pageService.findJobInfo(uuid));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.company.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public record JobInfoDto(@Getter String title, @Getter String description) {
|
||||
public JobInfoDto(String title, String description) {
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.company.dto;
|
||||
|
||||
import com.company.model.Page;
|
||||
import lombok.Getter;
|
||||
|
||||
public record PageDto(@Getter String jobUrl) {
|
||||
public PageDto(String jobUrl) {
|
||||
this.jobUrl = jobUrl;
|
||||
}
|
||||
|
||||
public static Page toPage(PageDto pageDto) {
|
||||
return Page.builder()
|
||||
.jobUrl(pageDto.getJobUrl())
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.company.exception;
|
||||
|
||||
public class PageNotFoundException extends Exception {
|
||||
public PageNotFoundException() {
|
||||
}
|
||||
|
||||
public PageNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.company.model;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "pages")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class Page {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private UUID id;
|
||||
private String jobUrl;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.company.repo;
|
||||
|
||||
import com.company.model.Page;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface PageRepository extends JpaRepository<Page, UUID> {
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.company.service;
|
||||
|
||||
import com.company.dto.JobInfoDto;
|
||||
import com.company.dto.PageDto;
|
||||
import com.company.model.Page;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface PageService {
|
||||
Page save(PageDto pageDto);
|
||||
List<Page> findAll();
|
||||
Optional<Page> findPageByUUID(UUID uuid);
|
||||
JobInfoDto findJobInfo(UUID jobUUID);
|
||||
Page updatePageByUUID(UUID uuid, PageDto pageDto);
|
||||
UUID deletePageByUUID(UUID uuid);
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.company.service.impl;
|
||||
|
||||
import com.company.dto.JobInfoDto;
|
||||
import com.company.dto.PageDto;
|
||||
import com.company.model.Page;
|
||||
import com.company.repo.PageRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class PageService implements com.company.service.PageService {
|
||||
private final PageRepository pageRepository;
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
@Autowired
|
||||
public PageService(PageRepository pageRepository, RestTemplate restTemplate) {
|
||||
this.pageRepository = pageRepository;
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Page save(PageDto pageDto) {
|
||||
return pageRepository.save(PageDto.toPage(pageDto));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public List<Page> findAll() {
|
||||
return pageRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Optional<Page> findPageByUUID(UUID uuid) {
|
||||
return Optional.ofNullable(pageRepository.findById(uuid).get());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Page updatePageByUUID(UUID uuid, PageDto pageDto) {
|
||||
Page page = pageRepository.findById(uuid).get();
|
||||
page.setJobUrl(pageDto.getJobUrl());
|
||||
return pageRepository.save(page);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public UUID deletePageByUUID(UUID uuid) {
|
||||
pageRepository.deleteById(uuid);
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public JobInfoDto findJobInfo(UUID jobUUID) {
|
||||
String jobInfoUrl = "http://nginx/aggregator-api/jobs/" + jobUUID;
|
||||
return restTemplate.getForObject(jobInfoUrl, JobInfoDto.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
spring:
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
show-sql: true
|
||||
datasource:
|
||||
driverClassName: org.postgresql.Driver
|
||||
url: jdbc:postgresql://localhost:5433/aggregator_db
|
||||
username: postgres
|
||||
password: postgres
|
@ -0,0 +1,13 @@
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
spring:
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
show-sql: true
|
||||
datasource:
|
||||
driverClassName: org.postgresql.Driver
|
||||
url: jdbc:postgresql://localhost:5433/aggregator_db
|
||||
username: postgres
|
||||
password: postgres
|
@ -0,0 +1,3 @@
|
||||
artifactId=parser-api
|
||||
groupId=com.company
|
||||
version=1.0-SNAPSHOT
|
@ -0,0 +1,10 @@
|
||||
com/company/service/impl/PageService.class
|
||||
com/company/dto/PageDto.class
|
||||
com/company/model/Page.class
|
||||
com/company/service/PageService.class
|
||||
com/company/repo/PageRepository.class
|
||||
com/company/model/Page$PageBuilder.class
|
||||
com/company/dto/JobInfoDto.class
|
||||
com/company/controller/PageController.class
|
||||
com/company/ParserApiApplication.class
|
||||
com/company/exception/PageNotFoundException.class
|
@ -0,0 +1,9 @@
|
||||
/Users/a-shdv/IdeaProjects/aggregator/parser-api/src/main/java/com/company/ParserApiApplication.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/parser-api/src/main/java/com/company/controller/PageController.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/parser-api/src/main/java/com/company/model/Page.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/parser-api/src/main/java/com/company/service/PageService.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/parser-api/src/main/java/com/company/exception/PageNotFoundException.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/parser-api/src/main/java/com/company/service/impl/PageService.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/parser-api/src/main/java/com/company/dto/PageDto.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/parser-api/src/main/java/com/company/dto/JobInfoDto.java
|
||||
/Users/a-shdv/IdeaProjects/aggregator/parser-api/src/main/java/com/company/repo/PageRepository.java
|
38
shadaev_anton_lab_3/pom.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<?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>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.7.5</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.company</groupId>
|
||||
<artifactId>shadaev_anton_lab_3</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>aggregator-api</module>
|
||||
<module>parser-api</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
BIN
shadaev_anton_lab_3/screenshots/1.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
shadaev_anton_lab_3/screenshots/2.png
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
shadaev_anton_lab_3/screenshots/3.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
shadaev_anton_lab_3/screenshots/4.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
shadaev_anton_lab_3/screenshots/5.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
shadaev_anton_lab_3/screenshots/img.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
shadaev_anton_lab_3/screenshots/img_1.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
shadaev_anton_lab_3/screenshots/img_10.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
shadaev_anton_lab_3/screenshots/img_11.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
shadaev_anton_lab_3/screenshots/img_12.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
shadaev_anton_lab_3/screenshots/img_2.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
shadaev_anton_lab_3/screenshots/img_3.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
shadaev_anton_lab_3/screenshots/img_4.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
shadaev_anton_lab_3/screenshots/img_5.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
shadaev_anton_lab_3/screenshots/img_6.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
shadaev_anton_lab_3/screenshots/img_7.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
shadaev_anton_lab_3/screenshots/img_8.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
shadaev_anton_lab_3/screenshots/img_9.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
shadaev_anton_lab_3/screenshots/test/img.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
shadaev_anton_lab_3/screenshots/test/img_1.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
shadaev_anton_lab_3/screenshots/test/img_2.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
shadaev_anton_lab_3/screenshots/test/img_3.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
shadaev_anton_lab_3/screenshots/test/img_4.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
shadaev_anton_lab_3/screenshots/test/img_5.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
shadaev_anton_lab_3/screenshots/test/img_6.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
shadaev_anton_lab_3/screenshots/test/img_7.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
shadaev_anton_lab_3/screenshots/test/img_8.png
Normal file
After Width: | Height: | Size: 50 KiB |