Add client persistence

This commit is contained in:
litoral05
2026-06-03 10:16:48 +01:00
parent 2e5f7aecf8
commit cf0f79d0ff
10 changed files with 208 additions and 25 deletions
Binary file not shown.
+20
View File
@@ -30,6 +30,26 @@
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-community-dialects</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
@@ -1,13 +1,15 @@
package com.litoralregas.backend_gateway;
import com.litoralregas.backend_gateway.gateway.ProxyProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties(ProxyProperties.class)
public class BackendGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(BackendGatewayApplication.class, args);
}
}
}
@@ -1,4 +1,56 @@
package com.litoralregas.backend_gateway.client;
import jakarta.persistence.*;
@Entity
@Table(name = "clients")
public class ClientEntity {
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String name;
@Column(name = "backend_base_url", nullable = false)
private String backendBaseUrl;
@Column(nullable = false)
private boolean enabled = true;
@Column(name = "created_at", nullable = false, insertable = false, updatable = false)
private String createdAt;
public Long getId() {
return id;
}
public String getName() {
return name;
}
public String getBackendBaseUrl() {
return backendBaseUrl;
}
public boolean isEnabled() {
return enabled;
}
public String getCreatedAt() {
return createdAt;
}
public void setName(String name) {
this.name = name;
}
public void setBackendBaseUrl(String backendBaseUrl) {
this.backendBaseUrl = backendBaseUrl;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
@@ -1,4 +1,10 @@
package com.litoralregas.backend_gateway.client;
public class ClientRepository {
}
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface ClientRepository extends JpaRepository<ClientEntity, Long> {
Optional<ClientEntity> findByName(String name);
}
@@ -1,14 +1,25 @@
package com.litoralregas.backend_gateway.config;
import com.litoralregas.backend_gateway.gateway.ProxyProperties;
import io.netty.channel.ChannelOption;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient(WebClient.Builder builder) {
return builder.build();
public WebClient webClient(WebClient.Builder builder, ProxyProperties proxyProperties) {
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,
Math.toIntExact(proxyProperties.getConnectTimeout().toMillis()))
.responseTimeout(proxyProperties.getResponseTimeout());
return builder
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
}
@@ -1,48 +1,79 @@
package com.litoralregas.backend_gateway.gateway;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
@Service
public class BackendProxyService {
private final WebClient webClient;
private final String devBackendUrl;
private final ProxyProperties proxyProperties;
public BackendProxyService(
WebClient webClient,
@Value("${gateway.dev-backend-url}") String devBackendUrl
) {
public BackendProxyService(WebClient webClient, ProxyProperties proxyProperties) {
this.webClient = webClient;
this.devBackendUrl = devBackendUrl;
this.proxyProperties = proxyProperties;
}
public String getHealth() {
return webClient.get()
.uri(devBackendUrl + "/actuator/health")
.uri(proxyProperties.getBackendBaseUrl() + "/actuator/health")
.retrieve()
.bodyToMono(String.class)
.block();
}
public ResponseEntity<String> proxy(HttpServletRequest request, String body) {
String path = request.getRequestURI().replaceFirst("/api/backend", "");
String query = request.getQueryString();
String targetUrl = devBackendUrl + path + (query != null ? "?" + query : "");
String targetUrl =
proxyProperties.getBackendBaseUrl()
+ path
+ (query != null ? "?" + query : "");
String response = webClient
.method(HttpMethod.valueOf(request.getMethod()))
.uri(targetUrl)
.bodyValue(body != null ? body : "")
.retrieve()
.bodyToMono(String.class)
.block();
try {
WebClient.RequestBodySpec requestSpec = webClient
.method(HttpMethod.valueOf(request.getMethod()))
.uri(targetUrl);
return ResponseEntity.ok(response);
String contentType = request.getContentType();
if (contentType != null) {
requestSpec.header("Content-Type", contentType);
}
String accept = request.getHeader("Accept");
if (accept != null) {
requestSpec.header("Accept", accept);
}
ResponseEntity<String> response = requestSpec
.bodyValue(body != null ? body : "")
.retrieve()
.toEntity(String.class)
.block();
return ResponseEntity
.status(response.getStatusCode())
.headers(response.getHeaders())
.body(response.getBody());
} catch (WebClientResponseException ex) {
return ResponseEntity
.status(ex.getStatusCode())
.body(ex.getResponseBodyAsString());
} catch (Exception ex) {
return ResponseEntity
.status(HttpStatus.BAD_GATEWAY)
.body("Backend unavailable");
}
}
}
@@ -0,0 +1,37 @@
package com.litoralregas.backend_gateway.gateway;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.time.Duration;
@ConfigurationProperties(prefix = "gateway.proxy")
public class ProxyProperties {
private String backendBaseUrl;
private Duration connectTimeout = Duration.ofSeconds(3);
private Duration responseTimeout = Duration.ofSeconds(10);
public String getBackendBaseUrl() {
return backendBaseUrl;
}
public void setBackendBaseUrl(String backendBaseUrl) {
this.backendBaseUrl = backendBaseUrl;
}
public Duration getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(Duration connectTimeout) {
this.connectTimeout = connectTimeout;
}
public Duration getResponseTimeout() {
return responseTimeout;
}
public void setResponseTimeout(Duration responseTimeout) {
this.responseTimeout = responseTimeout;
}
}
+18 -1
View File
@@ -5,5 +5,22 @@ spring:
application:
name: backend-gateway
datasource:
url: jdbc:sqlite:./data/backend-gateway.db
driver-class-name: org.sqlite.JDBC
jpa:
database-platform: org.hibernate.community.dialect.SQLiteDialect
hibernate:
ddl-auto: none
show-sql: true
flyway:
enabled: true
locations: classpath:db/migration
gateway:
dev-backend-url: http://10.100.1.2:18450
proxy:
backend-base-url: http://10.100.1.2:18450
connect-timeout: 3s
response-timeout: 10s
@@ -0,0 +1,7 @@
CREATE TABLE clients (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
backend_base_url TEXT NOT NULL,
enabled INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);