Merge pull request 'tepechin_kirill_lab_3' (#41) from tepechin_kirill_lab_3 into main

Reviewed-on: http://student.git.athene.tech/Alexey/DAS_2023_1/pulls/41
This commit is contained in:
Alexey 2023-12-25 16:27:39 +04:00
commit c4c4873091
23 changed files with 593 additions and 0 deletions

View File

@ -0,0 +1,99 @@
## Лабораторная работа №3, ПИбд-42 Тепечин Кирилл
### Сервисы
* `opop-service`
* `document-service`
### Синхронный обмен между микросервисами
Синхронное взаимодействие осуществляется через `RestTemplate`
Пример взаимодействия:
````java
RestTemplate restTemplate = new RestTemplate();
String URL = "http://document-service:8081/document/";
restTemplate.getForObject(URL+ opopDto.getDocumentId(), DocumentInfo.class)
````
### Докерфайлы
````dockerfile
FROM eclipse-temurin:17-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
````
### docker-compose файл
````yaml
version: '3'
services:
opop-service:
build:
context: /opop-service
dockerfile: Dockerfile
args:
JAR_FILE: build/libs/*.jar
ports:
- "8080:8080"
networks:
- my-network
environment:
server.forward-headers-strategy: framework
document-service:
build:
context: /document-service
dockerfile: Dockerfile
args:
JAR_FILE: build/libs/*.jar
ports:
- "8081:8081"
networks:
- my-network
environment:
server.forward-headers-strategy: framework
nginx:
image: nginx
ports:
- "80:80"
networks:
- my-network
volumes:
- ./nginx-conf:/etc/nginx/conf.d
depends_on:
- opop-service
- document-service
networks:
my-network:
driver: bridge
````
### nginx.conf
````
server {
listen 80;
location /opop-service/ {
proxy_pass_request_headers on;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Prefix '/opop-service';
proxy_pass http://opop-service:8080/;
}
location /document-service/ {
proxy_pass_request_headers on;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Prefix '/document-service';
proxy_pass http://document-service:8081/;
}
}
````
### Ссылка на видео
https://vk.com/video170089763_456239482?list=ln-0DBU1KuruzjrZvKRLE

View File

@ -0,0 +1,43 @@
version: '3'
services:
opop-service:
build:
context: /opop-service
dockerfile: Dockerfile
args:
JAR_FILE: build/libs/*.jar
ports:
- "8080:8080"
networks:
- my-network
environment:
server.forward-headers-strategy: framework
document-service:
build:
context: /document-service
dockerfile: Dockerfile
args:
JAR_FILE: build/libs/*.jar
ports:
- "8081:8081"
networks:
- my-network
environment:
server.forward-headers-strategy: framework
nginx:
image: nginx
ports:
- "80:80"
networks:
- my-network
volumes:
- ./nginx-conf:/etc/nginx/conf.d
depends_on:
- opop-service
- document-service
networks:
my-network:
driver: bridge

View File

@ -0,0 +1,5 @@
FROM eclipse-temurin:17-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

View File

@ -0,0 +1,35 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.0'
id 'io.spring.dependency-management' version '1.1.0'
}
group = 'org.example'
version = '1.0-SNAPSHOT'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
// implementation 'org.mapstruct:mapstruct:1.5.3.Final'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.3'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final'
testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter'
}
test {
useJUnitPlatform()
}

View File

@ -0,0 +1,17 @@
package org.example;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonView;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Document {
@JsonView(Views.Private.class)
private long id;
@JsonView(Views.Public.class)
private String text;
}

View File

@ -0,0 +1,11 @@
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DocumentApplication {
public static void main(String[] args) {
SpringApplication.run(DocumentApplication.class, args);
}
}

View File

@ -0,0 +1,48 @@
package org.example;
import com.fasterxml.jackson.annotation.JsonView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/document")
public class DocumentController {
@Autowired
private DocumentStorage documentStorage;
@JsonView(Views.Private.class)
@GetMapping
public List<Document> getAllDocuments(){
return documentStorage.getAllDocuments();
}
@JsonView(Views.Private.class)
@GetMapping("/{id}")
public Document getDocument(@PathVariable long id){
return documentStorage.getDocument(id);
}
@PostMapping
public Document addDocument(@RequestBody @JsonView(Views.Public.class) Document document){
return documentStorage.addDocument(document);
}
@PutMapping
public void editDocument(@RequestBody Document opopDtoList){
documentStorage.editDocument(opopDtoList);
}
@DeleteMapping("/{id}")
public void deleteDocument(@PathVariable long id){
documentStorage.deleteDocument(id);
}
@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler(Exception.class)
public String handleNotFound(Exception e) {
return e.getMessage();
}
}

View File

@ -0,0 +1,50 @@
package org.example;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class DocumentStorage {
private long currentId = 1;
private static final List<Document> documentList = new ArrayList<>();
public List<Document> getAllDocuments(){
return documentList;
}
public Document getDocument(long id){
return documentList.get(findIndexById(id));
}
public Document addDocument(Document document){
long id = currentId++;
document.setId(id);
documentList.add(document);
return document;
}
public void deleteDocument(long id){
documentList.remove(documentList.get(findIndexById(id)));
}
public void editDocument(Document document){
int index = findIndexById(document.getId());
Document docFromDb = documentList.get(index);
docFromDb.setText(document.getText());
documentList.set(index, docFromDb);
}
private int findIndexById(long idToFind) {
for (int i = 0; i < documentList.size(); i++) {
Document obj = documentList.get(i);
if (obj.getId() == idToFind) {
return i;
}
}
return -1;
}
}

View File

@ -0,0 +1,6 @@
package org.example;
public class Views {
public interface Public {}
public interface Private extends Public {}
}

View File

@ -0,0 +1,3 @@
server:
port: 8081
forward-headers-strategy=framework:

View File

@ -0,0 +1,18 @@
server {
listen 80;
location /opop-service/ {
proxy_pass_request_headers on;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Prefix '/opop-service';
proxy_pass http://opop-service:8080/;
}
location /document-service/ {
proxy_pass_request_headers on;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Prefix '/document-service';
proxy_pass http://document-service:8081/;
}
}

View File

@ -0,0 +1,5 @@
FROM eclipse-temurin:17-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

View File

@ -0,0 +1,35 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.0'
id 'io.spring.dependency-management' version '1.1.0'
}
group = 'org.example'
version = '1.0-SNAPSHOT'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.mapstruct:mapstruct:1.5.3.Final'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.3'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final'
testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter'
}
test {
useJUnitPlatform()
}

View File

@ -0,0 +1,17 @@
package org.example;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.example.dto.DocumentInfo;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Opop {
private long id;
private String code;
private int studyDuration;
private DocumentInfo documentInfo;
}

View File

@ -0,0 +1,11 @@
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OpopApplication {
public static void main(String[] args) {
SpringApplication.run(OpopApplication.class, args);
}
}

View File

@ -0,0 +1,49 @@
package org.example;
import org.example.dto.OpopDtoCreate;
import org.example.dto.OpopDtoDetails;
import org.example.dto.OpopDtoList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/opop")
public class OpopController {
@Autowired
private OpopStorage opopStorage;
@GetMapping
public List<OpopDtoList> getAllOpops(){
return opopStorage.getAllOpops();
}
@GetMapping("/{id}")
public OpopDtoDetails getOpopDetails(@PathVariable long id){
return opopStorage.getOpopDetails(id);
}
@PostMapping
public OpopDtoDetails addOpop(@RequestBody OpopDtoCreate opopDtoCreate){
return opopStorage.addOpop(opopDtoCreate);
}
@PutMapping
public void editOpop(@RequestBody OpopDtoList opopDtoList){
opopStorage.editOpop(opopDtoList);
}
@DeleteMapping("/{id}")
public void deleteOpop(@PathVariable long id){
opopStorage.deleteOpop(id);
}
@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler(Exception.class)
public String handleNotFound(Exception e) {
return e.getMessage();
}
}

View File

@ -0,0 +1,17 @@
package org.example;
import org.example.dto.OpopDtoCreate;
import org.example.dto.OpopDtoDetails;
import org.example.dto.OpopDtoList;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface OpopMapper {
@Mapping(target = "documentId", source = "documentInfo.id")
OpopDtoList toListDto(Opop opop);
OpopDtoDetails toDetailsDto(Opop opop);
@Mapping(source = "documentId", target = "documentInfo.id")
Opop fromCreateDto(OpopDtoCreate opopDtoCreate);
}

View File

@ -0,0 +1,65 @@
package org.example;
import org.example.dto.DocumentInfo;
import org.example.dto.OpopDtoCreate;
import org.example.dto.OpopDtoDetails;
import org.example.dto.OpopDtoList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
@Component
public class OpopStorage {
@Autowired
private OpopMapper opopMapper;
private long currentId = 1;
private final RestTemplate restTemplate = new RestTemplate();
private static final List<Opop> opopList = new ArrayList<>();
private final String URL = "http://document-service:8081/document/";
public List<OpopDtoList> getAllOpops(){
return opopList.stream().map(opop -> opopMapper.toListDto(opop)).toList();
}
public OpopDtoDetails getOpopDetails(long id){
return opopMapper.toDetailsDto(opopList.stream()
.filter(opop -> opop.getId() == id).toList().get(0));
}
public OpopDtoDetails addOpop(OpopDtoCreate opopDtoCreate){
long id = currentId++;
Opop opop = opopMapper.fromCreateDto(opopDtoCreate);
opop.setId(id);
opop.setDocumentInfo(restTemplate.getForObject(URL+ opopDtoCreate.getDocumentId(), DocumentInfo.class));
opopList.add(opop);
return opopMapper.toDetailsDto(opop);
}
public void deleteOpop(long id){
opopList.remove(opopList.stream().filter(opop -> opop.getId() == id).toList().get(0));
}
public void editOpop(OpopDtoList opopDto){
int index = findIndexById(opopDto.getId());
Opop opop = opopList.get(index);
opop.setCode(opopDto.getCode());
opop.setStudyDuration(opopDto.getStudyDuration());
opop.setDocumentInfo(restTemplate.getForObject(URL+ opopDto.getDocumentId(), DocumentInfo.class));
opopList.set(index, opop);
}
private int findIndexById(long idToFind) {
for (int i = 0; i < opopList.size(); i++) {
Opop obj = opopList.get(i);
if (obj.getId() == idToFind) {
return i;
}
}
return -1;
}
}

View File

@ -0,0 +1,13 @@
package org.example.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DocumentInfo {
private long id;
private String text;
}

View File

@ -0,0 +1,14 @@
package org.example.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OpopDtoCreate {
private String code;
private int studyDuration;
private int documentId;
}

View File

@ -0,0 +1,15 @@
package org.example.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OpopDtoDetails {
private long id;
private String code;
private int studyDuration;
private DocumentInfo documentInfo;
}

View File

@ -0,0 +1,15 @@
package org.example.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OpopDtoList {
private long id;
private String code;
private int studyDuration;
private int documentId;
}

View File

@ -0,0 +1,2 @@
server:
forward-headers-strategy=framework: