Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
dc955f6
add compilable annotations of mapstruct in project (fase 1: compile)
YrioTries Aug 13, 2025
b70892f
add constructor in mappers
YrioTries Aug 14, 2025
9363551
add id field in BookingRequestDto
YrioTries Aug 14, 2025
7bf83cb
transit to annotation mapper of booking
YrioTries Aug 14, 2025
0b9fcab
transit to annotation mapper of booking in ItemServiceImpl
YrioTries Aug 14, 2025
5c95419
transit to annotation mapper of item in ItemServiceImpl
YrioTries Aug 14, 2025
c06bcd2
transit to annotation mapper of user in UserServiceImpl
YrioTries Aug 14, 2025
ffe797c
transit to annotation mapper of user in UserServiceImpl
YrioTries Aug 15, 2025
6158aca
delete files
YrioTries Aug 15, 2025
d96aef1
rename UserMapper interface
YrioTries Aug 15, 2025
533719f
oh...
YrioTries Aug 18, 2025
4e92bbc
add BookingClient
YrioTries Aug 18, 2025
9df158d
delete ResponseEntity from server's BookingController
YrioTries Aug 18, 2025
04eaefa
add gateway's BookingController
YrioTries Aug 18, 2025
e8c2593
add @RequiredArgsConstructor in server controllers
YrioTries Aug 18, 2025
492f1f0
add requestor field in item
YrioTries Aug 19, 2025
9b92d2f
replacing files in package ItemRequest
YrioTries Aug 19, 2025
c6e8f1f
edit ItemRequest and ItemRequestDto
YrioTries Aug 19, 2025
0c53ec2
add ItemRequestService and ItemRequestServiceImpl.java
YrioTries Aug 19, 2025
f976adc
add ItemRequestController
YrioTries Aug 19, 2025
4110436
add ItemRequestMapper
YrioTries Aug 19, 2025
54111f1
add ItemRequestController
YrioTries Aug 19, 2025
ce018b6
delete comment in ItemRequestMapper
YrioTries Aug 19, 2025
a343b2e
fix small annotation
YrioTries Aug 22, 2025
7c0a8ff
fix ItemRequestServiceImpl.java
YrioTries Aug 22, 2025
69735a1
delete useless annotation
YrioTries Aug 22, 2025
00eb579
edit application.properties
YrioTries Aug 22, 2025
e896577
edit application.properties
YrioTries Aug 22, 2025
72d5cc7
add postgre in server pom
YrioTries Aug 22, 2025
00a52f6
add dto's in gateway
YrioTries Aug 26, 2025
50489ff
edit import of ItemDto
YrioTries Aug 26, 2025
8d915fa
delete dependency of server in gateway pom
YrioTries Aug 26, 2025
0b7af96
add constructor annotations to clients
YrioTries Aug 27, 2025
08d4717
add cashing
YrioTries Aug 27, 2025
8228263
add ItemRequest logic in gateway
YrioTries Aug 27, 2025
9d6d91f
fix import in ItemRequestDto
YrioTries Aug 27, 2025
77b2a2c
add lost method to user
YrioTries Aug 28, 2025
ca29107
add logging
YrioTries Aug 28, 2025
20c60d5
delete "/" in client exchange
YrioTries Aug 28, 2025
1c2b793
refactoring gateway
YrioTries Aug 31, 2025
c2d2baf
15 errors
YrioTries Aug 31, 2025
b0b37b7
add mid results
YrioTries Aug 31, 2025
9818101
fix server mistake of ItemController with PathVariable
YrioTries Aug 31, 2025
f7ff79b
rename id to itemId
YrioTries Aug 31, 2025
90ae84d
add Valid
YrioTries Aug 31, 2025
0eb4411
delete item_request table and create it again
YrioTries Sep 1, 2025
23600d2
delete style problems
YrioTries Sep 1, 2025
be0760f
try to fix github bug
YrioTries Sep 1, 2025
5d8677b
try to fix github bug 2
YrioTries Sep 1, 2025
27f0968
delete import in ErrorHandler
YrioTries Sep 1, 2025
13c8a73
try to fix bug
YrioTries Sep 1, 2025
d3f1a9f
try to fix bug
YrioTries Sep 1, 2025
d685111
update docker net
YrioTries Sep 1, 2025
c0fd725
change dir
YrioTries Sep 1, 2025
f3eefcd
problem...
YrioTries Sep 1, 2025
03606c7
set docker
YrioTries Sep 1, 2025
ddab7a8
fix bug
YrioTries Sep 1, 2025
6609657
docker update
YrioTries Sep 1, 2025
16ea2de
????
YrioTries Sep 1, 2025
0771ad3
edit application.properties
YrioTries Sep 1, 2025
6813559
edit poms
YrioTries Sep 1, 2025
ad17df6
edit poms
YrioTries Sep 1, 2025
bce5e2e
add space
YrioTries Sep 1, 2025
2d3063b
start docker-compose.yaml
YrioTries Sep 1, 2025
dda8e2f
fix add comment
YrioTries Sep 2, 2025
45fb16e
1 error
YrioTries Sep 2, 2025
ef31f0d
try to solve timeout error
YrioTries Sep 2, 2025
53fcaf2
try to solve timeout error
YrioTries Sep 3, 2025
192bf20
delete Cacheable
YrioTries Sep 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 35 additions & 9 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,42 @@
version: '3.8'

volumes:
postgres_data:

services:
db:
image: postgres:16.1
ports:
- "5432:5432"
volumes:
- ./volumes/postgres:/var/lib/postgresql/data/
environment:
- POSTGRES_DB=shareit
- POSTGRES_USER=dbuser
- POSTGRES_PASSWORD=12345
POSTGRES_USER: dbuser
POSTGRES_PASSWORD: 12345
POSTGRES_DB: shareit
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER
timeout: 5s
interval: 5s
retries: 10
test: ["CMD-SHELL", "pg_isready -U dbuser -d shareit"]

server:
build:
context: .
dockerfile: server/Dockerfile
ports:
- "9090:9090"
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/shareit # ← db вместо postgres
- SPRING_DATASOURCE_USERNAME=dbuser
- SPRING_DATASOURCE_PASSWORD=12345
depends_on:
- db # ← зависит от db, а не postgres

gateway:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Конечно, лучше подождать, послушать, что скажет наставник. Они теперь как-то по-другому организовывают.
То что вижу я: избавиться от кириллицы, на всякий случай; вообще убрать всё лишнее …
Приблизительно, вот так:

  gateway:
    build: ./gateway
    image: gateway
    container_name: gateway
    ports:
      - "8080:8080"
    depends_on:
      - server
    environment:
      - SHAREIT_SERVER_URL=http://server:9090

И для сервера с базой данных аналогично

build:
context: .
dockerfile: gateway/Dockerfile
ports:
- "8080:8080"
environment:
- SHAREIT_SERVER_URL=http://server:9090
depends_on:
- server
5 changes: 5 additions & 0 deletions gateway/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM eclipse-temurin:21-jre-jammy
VOLUME /tmp
ARG JAR_FILE=gateway/target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"]
70 changes: 70 additions & 0 deletions gateway/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?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">
<parent>
<groupId>ru.practicum</groupId>
<artifactId>shareit</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gateway</artifactId>
<packaging>jar</packaging>

<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</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-validation</artifactId>
</dependency>


<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3.1</version>
</dependency>

<!-- Spring Cache -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-cache</artifactId>-->
<!-- </dependency>-->

<!-- Redis -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-data-redis</artifactId>-->
<!-- </dependency>-->
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>ru.practicum.gateway.ShareItAppGateWay</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package ru.practicum.shareit;
package ru.practicum.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ShareItApp {
public class ShareItAppGateWay {
public static void main(String[] args) {
SpringApplication.run(ShareItApp.class, args);
SpringApplication.run(ShareItAppGateWay.class, args);
}
}
126 changes: 126 additions & 0 deletions gateway/src/main/java/ru/practicum/gateway/base/BaseClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package ru.practicum.gateway.base;

import org.springframework.http.*;
import org.springframework.lang.Nullable;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Map;

public class BaseClient {
protected final RestTemplate rest;

public BaseClient(RestTemplate rest) {
this.rest = rest;
}

protected ResponseEntity<Object> get(String path) {
return get(path, null, null);
}

protected ResponseEntity<Object> get(String path, long userId) {
return get(path, userId, null);
}

protected ResponseEntity<Object> get(String path, Long userId, @Nullable Map<String, Object> parameters) {
return makeAndSendRequest(HttpMethod.GET, path, userId, parameters, null);
}

protected <T> ResponseEntity<Object> post(String path, T body) {
return post(path, null, null, body);
}

protected <T> ResponseEntity<Object> post(String path, long userId, T body) {
return post(path, userId, null, body);
}

protected <T> ResponseEntity<Object> post(String path, Long userId, @Nullable Map<String, Object> parameters, T body) {
return makeAndSendRequest(HttpMethod.POST, path, userId, parameters, body);
}

protected <T> ResponseEntity<Object> put(String path, long userId, T body) {
return put(path, userId, null, body);
}

protected <T> ResponseEntity<Object> put(String path, long userId, @Nullable Map<String, Object> parameters, T body) {
return makeAndSendRequest(HttpMethod.PUT, path, userId, parameters, body);
}

protected <T> ResponseEntity<Object> patch(String path, T body) {
return patch(path, null, null, body);
}

protected <T> ResponseEntity<Object> patch(String path, long userId) {
return patch(path, userId, null, null);
}

protected <T> ResponseEntity<Object> patch(String path, long userId, T body) {
return patch(path, userId, null, body);
}

protected <T> ResponseEntity<Object> patch(String path, Long userId, @Nullable Map<String, Object> parameters, T body) {
return makeAndSendRequest(HttpMethod.PATCH, path, userId, parameters, body);
}

protected ResponseEntity<Object> delete(String path) {
return delete(path, null, null);
}

protected ResponseEntity<Object> delete(String path, long userId) {
return delete(path, userId, null);
}

protected ResponseEntity<Object> delete(String path, Long userId, @Nullable Map<String, Object> parameters) {
return makeAndSendRequest(HttpMethod.DELETE, path, userId, parameters, null);
}

protected ResponseEntity<Object> getWithHeaders(String path, long userId) {
HttpHeaders headers = new HttpHeaders();
headers.set("X-Sharer-User-Id", String.valueOf(userId));
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
HttpEntity<?> requestEntity = new HttpEntity<>(headers);
return rest.exchange(path, HttpMethod.GET, requestEntity, Object.class);
}

private <T> ResponseEntity<Object> makeAndSendRequest(HttpMethod method, String path, Long userId, @Nullable Map<String, Object> parameters, @Nullable T body) {
HttpEntity<T> requestEntity = new HttpEntity<>(body, defaultHeaders(userId));

ResponseEntity<Object> shareitServerResponse;
try {
if (parameters != null) {
shareitServerResponse = rest.exchange(path, method, requestEntity, Object.class, parameters);
} else {
shareitServerResponse = rest.exchange(path, method, requestEntity, Object.class);
}
} catch (HttpStatusCodeException e) {
return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsByteArray());
}
return prepareGatewayResponse(shareitServerResponse);
}

private HttpHeaders defaultHeaders(Long userId) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
if (userId != null) {
headers.set("X-Sharer-User-Id", String.valueOf(userId));
}
return headers;
}

private static ResponseEntity<Object> prepareGatewayResponse(ResponseEntity<Object> response) {
if (response.getStatusCode().is2xxSuccessful()) {
return response;
}

ResponseEntity.BodyBuilder responseBuilder = ResponseEntity.status(response.getStatusCode());

if (response.hasBody()) {
return responseBuilder.body(response.getBody());
}

return responseBuilder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ru.practicum.gateway.config;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.HiddenHttpMethodFilter;

import java.util.List;

@Configuration
public class PatchMethodConfig {

@Bean
public FilterRegistrationBean<HiddenHttpMethodFilter> hiddenHttpMethodFilter() {
FilterRegistrationBean<HiddenHttpMethodFilter> filterRegistrationBean =
new FilterRegistrationBean<>(new HiddenHttpMethodFilter());
filterRegistrationBean.setUrlPatterns(List.of("/*"));
return filterRegistrationBean;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package ru.practicum.gateway.entity.booking;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.util.DefaultUriBuilderFactory;
import ru.practicum.gateway.base.BaseClient;

import java.util.Map;

@Service
public class BookingClient extends BaseClient {

private static final String API_PREFIX = "/bookings";

@Autowired
public BookingClient(@Value("${shareit-server.url}") String serverUrl, RestTemplateBuilder builder) {
super(
builder
.uriTemplateHandler(new DefaultUriBuilderFactory(serverUrl + API_PREFIX))
.requestFactory(() -> new HttpComponentsClientHttpRequestFactory())
.build()
);
}

// @CacheEvict(value = "bookings", allEntries = true)
public ResponseEntity<Object> createBooking(BookingRequestDto bookingRequestDto, Long userId) {
return post("", userId, bookingRequestDto);
}

// @CacheEvict(value = "bookings", key = "#bookingId")
public ResponseEntity<Object> approveBooking(Long bookingId, Boolean approved, Long userId) {
Map<String, Object> parameters = Map.of("approved", approved);
return patch("/" + bookingId + "?approved={approved}", userId, parameters, null);
}

// @Cacheable(value = "bookings", key = "#bookingId")
public ResponseEntity<Object> getBookingById(Long bookingId, Long userId) {
return get("/" + bookingId, userId);
}

// @Cacheable(value = "bookings", key = "'user_' + #userId + '_state_' + #state + '_from_' + #from + '_size_' + #size")
public ResponseEntity<Object> getUserBookings(Long userId, Status state, Integer from, Integer size) {
Map<String, Object> parameters = Map.of(
"state", state.name(),
"from", from,
"size", size
);
return get("?state={state}&from={from}&size={size}", userId, parameters);
}

// @Cacheable(value = "bookings", key = "'user_' + #ownerId + '_state_' + #state + '_from_' + #from + '_size_' + #size")
public ResponseEntity<Object> getOwnerBookings(Long ownerId, Status state, Integer from, Integer size) {
Map<String, Object> parameters = Map.of(
"state", state.name(),
"from", from,
"size", size
);
return get("/owner?state={state}&from={from}&size={size}", ownerId, parameters);
}

// @CacheEvict(value = "bookings", key = "#bookingId")
public ResponseEntity<Object> deleteBooking(long userId, Long bookingId) {
return delete("/" + bookingId, userId);
}

}
Loading