Initial implementation of BFF, search-api integration and eureka
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,6 +3,8 @@ target/
|
|||||||
.mvn/wrapper/maven-wrapper.jar
|
.mvn/wrapper/maven-wrapper.jar
|
||||||
!**/src/main/**/target/
|
!**/src/main/**/target/
|
||||||
!**/src/test/**/target/
|
!**/src/test/**/target/
|
||||||
|
.mvn
|
||||||
|
/bin/
|
||||||
|
|
||||||
### STS ###
|
### STS ###
|
||||||
.apt_generated
|
.apt_generated
|
||||||
|
@ -2,16 +2,20 @@
|
|||||||
FROM maven:3.9.6-eclipse-temurin-21 AS builder
|
FROM maven:3.9.6-eclipse-temurin-21 AS builder
|
||||||
WORKDIR /workspace
|
WORKDIR /workspace
|
||||||
COPY pom.xml .
|
COPY pom.xml .
|
||||||
RUN mvn dependency:go-offline -B
|
COPY main-app/pom.xml ./main-app/
|
||||||
COPY src ./src
|
COPY anyame-kodik-search-api/pom.xml ./anyame-kodik-search-api/
|
||||||
RUN mvn clean package -DskipTests
|
RUN --mount=type=cache,target=/root/.m2 mvn dependency:go-offline -B
|
||||||
|
COPY main-app/src ./main-app/src
|
||||||
|
COPY anyame-kodik-search-api/src ./anyame-kodik-search-api/src
|
||||||
|
|
||||||
|
RUN --mount=type=cache,target=/root/.m2 mvn clean package -DskipTests
|
||||||
|
|
||||||
# Create optimized runtime
|
# Create optimized runtime
|
||||||
FROM eclipse-temurin:21 AS app-build
|
FROM eclipse-temurin:21 AS app-build
|
||||||
ENV RELEASE=21
|
ENV RELEASE=21
|
||||||
|
|
||||||
WORKDIR /opt/build
|
WORKDIR /opt/build
|
||||||
COPY --from=builder /workspace/target/*.jar ./application.jar
|
COPY --from=builder /workspace/main-app/target/*.jar ./application.jar
|
||||||
|
|
||||||
RUN java -Djarmode=layertools -jar application.jar extract
|
RUN java -Djarmode=layertools -jar application.jar extract
|
||||||
RUN $JAVA_HOME/bin/jlink \
|
RUN $JAVA_HOME/bin/jlink \
|
||||||
|
167
anyame-kodik-search-api/pom.xml
Normal file
167
anyame-kodik-search-api/pom.xml
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
<?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>
|
||||||
|
<artifactId>anyame-bff-parent</artifactId>
|
||||||
|
<groupId>com.backend.vue.bff.service</groupId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>com.backend.vue.bff.service</groupId>
|
||||||
|
<artifactId>anyame-kodik-search-api</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>anyame-kodik-search-api</name>
|
||||||
|
<description>Search API for anyame-kodik</description>
|
||||||
|
|
||||||
|
<url />
|
||||||
|
<licenses>
|
||||||
|
<license />
|
||||||
|
</licenses>
|
||||||
|
<developers>
|
||||||
|
<developer />
|
||||||
|
</developers>
|
||||||
|
<scm>
|
||||||
|
<connection />
|
||||||
|
<developerConnection />
|
||||||
|
<tag />
|
||||||
|
<url />
|
||||||
|
</scm>
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||||
|
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||||
|
<swagger-annotations-version>1.6.3</swagger-annotations-version>
|
||||||
|
<jackson-databind-version>2.17.1</jackson-databind-version>
|
||||||
|
<jackson-version>2.17.1</jackson-version>
|
||||||
|
<jakarta.ws.rs-api-version>4.0.0</jakarta.ws.rs-api-version>
|
||||||
|
<retrofit-version>2.11.0</retrofit-version>
|
||||||
|
<jakarta-annotation-version>2.1.1</jakarta-annotation-version>
|
||||||
|
<beanvalidation-version>3.0.2</beanvalidation-version>
|
||||||
|
<oltu-version>1.0.1</oltu-version>
|
||||||
|
<junit-version>5.10.3</junit-version>
|
||||||
|
<javax-annotation-api.version>1.3.2</javax-annotation-api.version>
|
||||||
|
<jakarta-validation-api.version>3.1.1</jakarta-validation-api.version>
|
||||||
|
<jsr305.version>3.0.2</jsr305.version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.swagger</groupId>
|
||||||
|
<artifactId>swagger-annotations</artifactId>
|
||||||
|
<version>${swagger-annotations-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- @Nullable annotation -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.findbugs</groupId>
|
||||||
|
<artifactId>jsr305</artifactId>
|
||||||
|
<version>${jsr305.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.retrofit2</groupId>
|
||||||
|
<artifactId>retrofit</artifactId>
|
||||||
|
<version>${retrofit-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.retrofit2</groupId>
|
||||||
|
<artifactId>converter-scalars</artifactId>
|
||||||
|
<version>${retrofit-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.oltu.oauth2</groupId>
|
||||||
|
<artifactId>org.apache.oltu.oauth2.client</artifactId>
|
||||||
|
<version>${oltu-version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.oltu.oauth2</groupId>
|
||||||
|
<artifactId>common</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<!-- JSON processing: jackson -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.retrofit2</groupId>
|
||||||
|
<artifactId>converter-jackson</artifactId>
|
||||||
|
<version>${retrofit-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-core</artifactId>
|
||||||
|
<version>${jackson-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-annotations</artifactId>
|
||||||
|
<version>${jackson-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>${jackson-databind-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||||
|
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||||
|
<version>${jackson-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.ws.rs</groupId>
|
||||||
|
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||||
|
<version>${jakarta.ws.rs-api-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.annotation</groupId>
|
||||||
|
<artifactId>jakarta.annotation-api</artifactId>
|
||||||
|
<version>${jakarta-annotation-version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.annotation</groupId>
|
||||||
|
<artifactId>javax.annotation-api</artifactId>
|
||||||
|
<version>${javax-annotation-api.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/jakarta.validation/jakarta.validation-api -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.validation</groupId>
|
||||||
|
<artifactId>jakarta.validation-api</artifactId>
|
||||||
|
<version>${jakarta-validation-api.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- test dependencies -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<version>${junit-version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.openapitools</groupId>
|
||||||
|
<artifactId>openapi-generator-maven-plugin</artifactId>
|
||||||
|
<version>7.14.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>generate</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<inputSpec>${project.basedir}/src/main/resources/openapi.json</inputSpec>
|
||||||
|
<generatorName>java</generatorName>
|
||||||
|
<configOptions>
|
||||||
|
<library>retrofit2</library>
|
||||||
|
<apiPackage>com.backend.search.kodik.api</apiPackage>
|
||||||
|
<modelPackage>com.backend.search.kodik.model</modelPackage>
|
||||||
|
<openApiNullable>false</openApiNullable>
|
||||||
|
<useJakartaEe>true</useJakartaEe>
|
||||||
|
<serializationLibrary>jackson</serializationLibrary>
|
||||||
|
</configOptions>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
365
anyame-kodik-search-api/src/main/resources/openapi.json
Normal file
365
anyame-kodik-search-api/src/main/resources/openapi.json
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
{
|
||||||
|
"openapi": "3.1.0",
|
||||||
|
"info": {
|
||||||
|
"title": "OpenAPI definition",
|
||||||
|
"version": "v0"
|
||||||
|
},
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "http://localhost:8080",
|
||||||
|
"description": "Generated server url"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"/search": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"search-controller"
|
||||||
|
],
|
||||||
|
"operationId": "search",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "title",
|
||||||
|
"in": "query",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/KodikResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"schemas": {
|
||||||
|
"KodikResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"total": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"results": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"MaterialData": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"year": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"screenshots": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"countries": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"genres": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"actors": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"directors": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"producers": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"writers": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"composers": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"editors": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"designers": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"operators": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"anime_title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title_en": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"other_titles": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"other_titles_en": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"other_titles_jp": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"anime_license_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"anime_licensed_by": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"anime_kind": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"all_status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"anime_status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"anime_description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"poster_url": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"anime_poster_url": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"all_genres": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"anime_genres": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"anime_studios": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"kinopoisk_rating": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "double"
|
||||||
|
},
|
||||||
|
"kinopoisk_votes": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"imdb_rating": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "double"
|
||||||
|
},
|
||||||
|
"imdb_votes": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"shikimori_rating": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "double"
|
||||||
|
},
|
||||||
|
"shikimori_votes": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"premiere_world": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"aired_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"released_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"rating_mpaa": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"minimal_age": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"episodes_total": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"episodes_aired": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Result": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"translation": {
|
||||||
|
"$ref": "#/components/schemas/Translation"
|
||||||
|
},
|
||||||
|
"year": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"quality": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"camrip": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"lgbt": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"screenshots": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title_orig": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"other_title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"last_season": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"last_episode": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"episodes_count": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"kinopoisk_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"imdb_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"worldart_link": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"shikimori_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"blocked_countries": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"material_data": {
|
||||||
|
"$ref": "#/components/schemas/MaterialData"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Translation": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
112
main-app/pom.xml
Normal file
112
main-app/pom.xml
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
<?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 https://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>3.5.5</version>
|
||||||
|
<relativePath /> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>com.backend.vue.bff.service</groupId>
|
||||||
|
<artifactId>anyame-vue-bff</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>anyame-vue-bff</name>
|
||||||
|
<description>BFF for Vue frontend</description>
|
||||||
|
<url />
|
||||||
|
<licenses>
|
||||||
|
<license />
|
||||||
|
</licenses>
|
||||||
|
<developers>
|
||||||
|
<developer />
|
||||||
|
</developers>
|
||||||
|
<scm>
|
||||||
|
<connection />
|
||||||
|
<developerConnection />
|
||||||
|
<tag />
|
||||||
|
<url />
|
||||||
|
</scm>
|
||||||
|
<properties>
|
||||||
|
<java.version>21</java.version>
|
||||||
|
|
||||||
|
<retrofit.version>3.0.0</retrofit.version>
|
||||||
|
<spring-dotenv.version>4.0.0</spring-dotenv.version>
|
||||||
|
<springdoc-openapi-starter.version>2.8.9</springdoc-openapi-starter.version>
|
||||||
|
<spring-cloud.version>2025.0.0</spring-cloud.version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-cache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.retrofit2</groupId>
|
||||||
|
<artifactId>converter-jackson</artifactId>
|
||||||
|
<version>${retrofit.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.paulschwarz</groupId>
|
||||||
|
<artifactId>spring-dotenv</artifactId>
|
||||||
|
<version>${spring-dotenv.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springdoc</groupId>
|
||||||
|
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||||
|
<version>${springdoc-openapi-starter.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.backend.vue.bff.service</groupId>
|
||||||
|
<artifactId>anyame-kodik-search-api</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-dependencies</artifactId>
|
||||||
|
<version>${spring-cloud.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -1,4 +1,4 @@
|
|||||||
package com.backend.extractor.kodik.service.anyame.bff;
|
package com.backend.vue.bff.service;
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
@ -0,0 +1,107 @@
|
|||||||
|
package com.backend.vue.bff.service.config;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
|
import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
import com.backend.vue.bff.service.exception.ServiceUnavailableException;
|
||||||
|
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
public static final Logger logger = LoggerFactory.getLogger("GlobalExceptionHandler");
|
||||||
|
|
||||||
|
@ExceptionHandler({ UnsatisfiedDependencyException.class, BeanCreationException.class,
|
||||||
|
ServiceUnavailableException.class })
|
||||||
|
public ResponseEntity<ErrorResponse> handleServiceUnavailable(ServiceUnavailableException e) {
|
||||||
|
ErrorResponse error = new ErrorResponse(
|
||||||
|
"SERVICE_UNAVAILABLE",
|
||||||
|
e.getMessage(),
|
||||||
|
HttpStatus.SERVICE_UNAVAILABLE.value());
|
||||||
|
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(IOException.class)
|
||||||
|
public ResponseEntity<ErrorResponse> handleIOException(IOException e) {
|
||||||
|
ErrorResponse error = new ErrorResponse(
|
||||||
|
"API_CALL_FAILED",
|
||||||
|
"Failed to communicate with external service: " + e.getMessage(),
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||||
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
public ResponseEntity<ErrorResponse> handleGenericException(Exception e) {
|
||||||
|
logger.error("Exception type: {}", e.getClass().getSimpleName());
|
||||||
|
logger.error("Exception message: {}", e.getMessage());
|
||||||
|
|
||||||
|
Throwable cause = e.getCause();
|
||||||
|
while (cause != null) {
|
||||||
|
logger.error("Cause type: {}", cause.getClass().getSimpleName());
|
||||||
|
if (cause instanceof ServiceUnavailableException) {
|
||||||
|
return handleServiceUnavailable((ServiceUnavailableException) cause);
|
||||||
|
}
|
||||||
|
cause = cause.getCause();
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorResponse error = new ErrorResponse(
|
||||||
|
"INTERNAL_ERROR",
|
||||||
|
"An unexpected error occurred",
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||||
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ErrorResponse {
|
||||||
|
private String code;
|
||||||
|
private String message;
|
||||||
|
private int status;
|
||||||
|
private long timestamp;
|
||||||
|
|
||||||
|
public ErrorResponse(String code, String message, int status) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
this.status = status;
|
||||||
|
this.timestamp = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters and setters
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(String code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(int status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimestamp(long timestamp) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
package com.backend.vue.bff.service.config;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
import org.springframework.cloud.client.ServiceInstance;
|
||||||
|
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||||
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
|
||||||
|
import com.backend.search.kodik.ApiClient;
|
||||||
|
import com.backend.search.kodik.JSON;
|
||||||
|
import com.backend.search.kodik.api.SearchControllerApi;
|
||||||
|
import com.backend.vue.bff.service.exception.ServiceUnavailableException;
|
||||||
|
|
||||||
|
import retrofit2.Retrofit;
|
||||||
|
import retrofit2.converter.jackson.JacksonConverterFactory;
|
||||||
|
import retrofit2.converter.scalars.ScalarsConverterFactory;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableDiscoveryClient
|
||||||
|
public class SearchApiClientConfiguration {
|
||||||
|
|
||||||
|
private final DiscoveryClient discoveryClient;
|
||||||
|
|
||||||
|
public SearchApiClientConfiguration(DiscoveryClient discoveryClient) {
|
||||||
|
this.discoveryClient = discoveryClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Lazy
|
||||||
|
public FactoryBean<ApiClient> apiClientFactory() {
|
||||||
|
return new ApiClientFactoryBean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Lazy
|
||||||
|
public SearchControllerApi searchApi(ApiClient apiClient) {
|
||||||
|
return apiClient.createService(SearchControllerApi.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ApiClientFactoryBean implements FactoryBean<ApiClient> {
|
||||||
|
@Override
|
||||||
|
public ApiClient getObject() throws Exception {
|
||||||
|
ApiClient client = new ApiClient();
|
||||||
|
|
||||||
|
String baseUrl = resolveServiceUrl("ANYAME-KODIK-SEARCH-BACKEND");
|
||||||
|
|
||||||
|
JSON json = new JSON();
|
||||||
|
|
||||||
|
Retrofit.Builder adapterBuilder = new Retrofit.Builder()
|
||||||
|
.baseUrl(baseUrl)
|
||||||
|
.addConverterFactory(ScalarsConverterFactory.create())
|
||||||
|
.addConverterFactory(JacksonConverterFactory.create(json.getMapper()));
|
||||||
|
|
||||||
|
client.setAdapterBuilder(adapterBuilder);
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> getObjectType() {
|
||||||
|
return ApiClient.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSingleton() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveServiceUrl(String serviceName) {
|
||||||
|
List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
|
||||||
|
|
||||||
|
if (instances.isEmpty()) {
|
||||||
|
throw new ServiceUnavailableException();
|
||||||
|
}
|
||||||
|
|
||||||
|
ServiceInstance instance = instances.get(0);
|
||||||
|
String baseUrl = instance.getUri().toString();
|
||||||
|
|
||||||
|
if (!baseUrl.endsWith("/")) {
|
||||||
|
baseUrl = baseUrl + "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.backend.vue.bff.service.controller;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.backend.search.kodik.api.SearchControllerApi;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class TestController {
|
||||||
|
private final ObjectProvider<SearchControllerApi> controllerApiFactory;
|
||||||
|
|
||||||
|
public TestController(ObjectProvider<SearchControllerApi> controllerApiFactory) {
|
||||||
|
this.controllerApiFactory = controllerApiFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/test")
|
||||||
|
public String test() throws IOException {
|
||||||
|
SearchControllerApi api = controllerApiFactory.getObject();
|
||||||
|
return Integer.toString(api.search("Шарлотта").execute().body().getResults().size());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.backend.vue.bff.service.exception;
|
||||||
|
|
||||||
|
public class ServiceUnavailableException extends RuntimeException {
|
||||||
|
public ServiceUnavailableException() {
|
||||||
|
super("Service Unavailable");
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.backend.extractor.kodik.service.anyame.bff;
|
package com.backend.vue.bff.service;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
103
pom.xml
103
pom.xml
@ -1,19 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
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>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>com.backend.vue.bff.service</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>anyame-bff-parent</artifactId>
|
||||||
<version>3.5.5</version>
|
|
||||||
<relativePath /> <!-- lookup parent from repository -->
|
|
||||||
</parent>
|
|
||||||
<groupId>com.backend.extractor.kodik.service</groupId>
|
|
||||||
<artifactId>anyame-vue-bff</artifactId>
|
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<name>anyame-vue-bff</name>
|
<packaging>pom</packaging>
|
||||||
<description>BFF for Vue frontend</description>
|
<name>anyame-bff-parent</name>
|
||||||
|
<description>Parent project for anyame-vue-bff</description>
|
||||||
|
|
||||||
<url />
|
<url />
|
||||||
<licenses>
|
<licenses>
|
||||||
<license />
|
<license />
|
||||||
@ -29,79 +26,15 @@
|
|||||||
</scm>
|
</scm>
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>21</java.version>
|
<java.version>21</java.version>
|
||||||
|
|
||||||
<retrofit.version>3.0.0</retrofit.version>
|
|
||||||
<spring-dotenv.version>4.0.0</spring-dotenv.version>
|
|
||||||
<springdoc-openapi-starter.version>2.8.9</springdoc-openapi-starter.version>
|
|
||||||
<spring-cloud.version>2025.0.0</spring-cloud.version>
|
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<modules>
|
||||||
<dependency>
|
<module>anyame-kodik-search-api</module>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<module>main-app</module>
|
||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
</modules>
|
||||||
</dependency>
|
<pluginRepositories>
|
||||||
<dependency>
|
<pluginRepository>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<id>openapi-generator-repo</id>
|
||||||
<artifactId>spring-boot-starter-cache</artifactId>
|
<url>https://raw.githubusercontent.com/OpenAPITools/openapi-generator/master/maven-plugins/repository</url>
|
||||||
</dependency>
|
</pluginRepository>
|
||||||
<dependency>
|
</pluginRepositories>
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.squareup.retrofit2</groupId>
|
|
||||||
<artifactId>converter-jackson</artifactId>
|
|
||||||
<version>${retrofit.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>me.paulschwarz</groupId>
|
|
||||||
<artifactId>spring-dotenv</artifactId>
|
|
||||||
<version>${spring-dotenv.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springdoc</groupId>
|
|
||||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
|
||||||
<version>${springdoc-openapi-starter.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-dependencies</artifactId>
|
|
||||||
<version>${spring-cloud.version}</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</dependencyManagement>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
Reference in New Issue
Block a user