From c4e91098bd876d15acc6c920c12d26fe4acb0622 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 4 Sep 2025 23:57:08 +0300 Subject: [PATCH 1/9] stat_svc_all_postman --- ewm-main-svc/Dockerfile | 5 ++ ewm-main-svc/pom.xml | 50 +++++++++++++ .../main/java/ru/practicum/ewm/MainApp.java | 11 +++ .../src/main/resources/application.properties | 7 ++ pom.xml | 4 ++ stat-svc/pom.xml | 34 +++++++++ stat-svc/stat-client/pom.xml | 41 +++++++++++ .../ru/practicum/stat/StatisticsClient.java | 60 ++++++++++++++++ .../ru/practicum/stat/base/BaseClient.java | 55 ++++++++++++++ stat-svc/stat-dto/pom.xml | 43 +++++++++++ .../practicum/stat/EndpointHitCreateDto.java | 24 +++++++ .../ru/practicum/stat/EndpointHitDto.java | 19 +++++ .../java/ru/practicum/stat/ViewStatsDto.java | 15 ++++ stat-svc/stat-server/Dockerfile | 5 ++ stat-svc/stat-server/pom.xml | 72 +++++++++++++++++++ .../practicum/stat/EndpointHitRepository.java | 42 +++++++++++ .../ru/practicum/stat/StatisticsServer.java | 11 +++ .../stat/controller/StatsController.java | 38 ++++++++++ .../stat/exception/ErrorHandler.java | 18 +++++ .../stat/exception/ErrorResponse.java | 11 +++ .../stat/mapper/EndpointHitMapper.java | 27 +++++++ .../stat/mapper/ViewStatsMapper.java | 15 ++++ .../ru/practicum/stat/model/EndpointHit.java | 28 ++++++++ .../ru/practicum/stat/model/ViewStats.java | 15 ++++ .../stat/service/StatisticsService.java | 14 ++++ .../stat/service/StatisticsServiceImpl.java | 61 ++++++++++++++++ .../main/resources/application-h2.properties | 5 ++ .../resources/application-postgres.properties | 5 ++ .../src/main/resources/application.properties | 10 +++ .../stat-server/src/main/resources/schema.sql | 9 +++ 30 files changed, 754 insertions(+) create mode 100644 ewm-main-svc/Dockerfile create mode 100644 ewm-main-svc/pom.xml create mode 100644 ewm-main-svc/src/main/java/ru/practicum/ewm/MainApp.java create mode 100644 ewm-main-svc/src/main/resources/application.properties create mode 100644 stat-svc/pom.xml create mode 100644 stat-svc/stat-client/pom.xml create mode 100644 stat-svc/stat-client/src/main/java/ru/practicum/stat/StatisticsClient.java create mode 100644 stat-svc/stat-client/src/main/java/ru/practicum/stat/base/BaseClient.java create mode 100644 stat-svc/stat-dto/pom.xml create mode 100644 stat-svc/stat-dto/src/main/java/ru/practicum/stat/EndpointHitCreateDto.java create mode 100644 stat-svc/stat-dto/src/main/java/ru/practicum/stat/EndpointHitDto.java create mode 100644 stat-svc/stat-dto/src/main/java/ru/practicum/stat/ViewStatsDto.java create mode 100644 stat-svc/stat-server/Dockerfile create mode 100644 stat-svc/stat-server/pom.xml create mode 100644 stat-svc/stat-server/src/main/java/ru/practicum/stat/EndpointHitRepository.java create mode 100644 stat-svc/stat-server/src/main/java/ru/practicum/stat/StatisticsServer.java create mode 100644 stat-svc/stat-server/src/main/java/ru/practicum/stat/controller/StatsController.java create mode 100644 stat-svc/stat-server/src/main/java/ru/practicum/stat/exception/ErrorHandler.java create mode 100644 stat-svc/stat-server/src/main/java/ru/practicum/stat/exception/ErrorResponse.java create mode 100644 stat-svc/stat-server/src/main/java/ru/practicum/stat/mapper/EndpointHitMapper.java create mode 100644 stat-svc/stat-server/src/main/java/ru/practicum/stat/mapper/ViewStatsMapper.java create mode 100644 stat-svc/stat-server/src/main/java/ru/practicum/stat/model/EndpointHit.java create mode 100644 stat-svc/stat-server/src/main/java/ru/practicum/stat/model/ViewStats.java create mode 100644 stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsService.java create mode 100644 stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsServiceImpl.java create mode 100644 stat-svc/stat-server/src/main/resources/application-h2.properties create mode 100644 stat-svc/stat-server/src/main/resources/application-postgres.properties create mode 100644 stat-svc/stat-server/src/main/resources/application.properties create mode 100644 stat-svc/stat-server/src/main/resources/schema.sql diff --git a/ewm-main-svc/Dockerfile b/ewm-main-svc/Dockerfile new file mode 100644 index 0000000..0ff1817 --- /dev/null +++ b/ewm-main-svc/Dockerfile @@ -0,0 +1,5 @@ +FROM eclipse-temurin:21-jre-jammy +VOLUME /tmp +ARG JAR_FILE=target/*.jar +COPY ${JAR_FILE} app.jar +ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] \ No newline at end of file diff --git a/ewm-main-svc/pom.xml b/ewm-main-svc/pom.xml new file mode 100644 index 0000000..d400a70 --- /dev/null +++ b/ewm-main-svc/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + ru.practicum + explore-with-me + 0.0.1-SNAPSHOT + + + ewm-main-svc + + + 22 + 22 + UTF-8 + + + + + + org.apache.httpcomponents.client5 + httpclient5 + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + true + + + + \ No newline at end of file diff --git a/ewm-main-svc/src/main/java/ru/practicum/ewm/MainApp.java b/ewm-main-svc/src/main/java/ru/practicum/ewm/MainApp.java new file mode 100644 index 0000000..908ca46 --- /dev/null +++ b/ewm-main-svc/src/main/java/ru/practicum/ewm/MainApp.java @@ -0,0 +1,11 @@ +package ru.practicum.ewm; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MainApp { + public static void main(String[] args) { + SpringApplication.run(MainApp.class, args); + } +} \ No newline at end of file diff --git a/ewm-main-svc/src/main/resources/application.properties b/ewm-main-svc/src/main/resources/application.properties new file mode 100644 index 0000000..68918f8 --- /dev/null +++ b/ewm-main-svc/src/main/resources/application.properties @@ -0,0 +1,7 @@ +logging.level.org.springframework.web.client.RestTemplate=DEBUG +#logging.level.org.apache.http=DEBUG +#logging.level.httpclient.wire=DEBUG + +server.port=8080 + +stat-server.url=${STAT_SERVER_URL:http://localhost:9090} \ No newline at end of file diff --git a/pom.xml b/pom.xml index b15acb2..f43f89d 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,10 @@ Explore With Me + + ewm-main-svc + stat-svc + ru.practicum explore-with-me diff --git a/stat-svc/pom.xml b/stat-svc/pom.xml new file mode 100644 index 0000000..2f46f6e --- /dev/null +++ b/stat-svc/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + ru.practicum + explore-with-me + 0.0.1-SNAPSHOT + + + stat-svc + pom + + + stat-client + stat-dto + stat-server + + + + 22 + 22 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + \ No newline at end of file diff --git a/stat-svc/stat-client/pom.xml b/stat-svc/stat-client/pom.xml new file mode 100644 index 0000000..6011f30 --- /dev/null +++ b/stat-svc/stat-client/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + ru.practicum + explore-with-me + 0.0.1-SNAPSHOT + ../../pom.xml + + + stat-client + + + 22 + 22 + UTF-8 + + + + + ru.practicum + stat-dto + 0.0.1-SNAPSHOT + compile + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + \ No newline at end of file diff --git a/stat-svc/stat-client/src/main/java/ru/practicum/stat/StatisticsClient.java b/stat-svc/stat-client/src/main/java/ru/practicum/stat/StatisticsClient.java new file mode 100644 index 0000000..212f121 --- /dev/null +++ b/stat-svc/stat-client/src/main/java/ru/practicum/stat/StatisticsClient.java @@ -0,0 +1,60 @@ +package ru.practicum.stat; + +import jakarta.servlet.http.HttpServletRequest; +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.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.util.DefaultUriBuilderFactory; +import org.springframework.web.util.UriComponentsBuilder; +import ru.practicum.stat.base.BaseClient; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +@Service +public class StatisticsClient extends BaseClient { + + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + private final String appName; + + @Autowired + public StatisticsClient(@Value("${stat-server.url}") String serverUrl, + @Value("${app.name}") String appName, + RestTemplateBuilder builder) { + super( + builder + .uriTemplateHandler(new DefaultUriBuilderFactory(serverUrl)) + .requestFactory(() -> new HttpComponentsClientHttpRequestFactory()) + .build() + ); + this.appName = appName; + } + + public ResponseEntity create(HttpServletRequest request) { + EndpointHitCreateDto endpointHitCreateDto = EndpointHitCreateDto.builder() + .app(appName) + .uri(request.getRequestURI()) + .ip(request.getRemoteAddr()) + .timestamp(LocalDateTime.now()) + .build(); + return post(endpointHitCreateDto); + } + + public ResponseEntity getStats(LocalDateTime start, LocalDateTime end, List uris, Boolean unique) { + UriComponentsBuilder builder = UriComponentsBuilder.fromPath("/stats") + .queryParam("start", start.format(formatter)) + .queryParam("end", end.format(formatter)) + .queryParam("unique", unique); + + if (uris != null && !uris.isEmpty()) { + builder.queryParam("uris", String.join(",", uris)); + } + String url = builder.toUriString(); + return get(url); + } +} \ No newline at end of file diff --git a/stat-svc/stat-client/src/main/java/ru/practicum/stat/base/BaseClient.java b/stat-svc/stat-client/src/main/java/ru/practicum/stat/base/BaseClient.java new file mode 100644 index 0000000..9cc744b --- /dev/null +++ b/stat-svc/stat-client/src/main/java/ru/practicum/stat/base/BaseClient.java @@ -0,0 +1,55 @@ +package ru.practicum.stat.base; + +import org.springframework.http.*; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; + +import java.util.List; + +public class BaseClient { + + protected final RestTemplate rest; + + public BaseClient(RestTemplate rest) { + this.rest = rest; + } + + protected ResponseEntity get(String path) { + return makeAndSendRequest(path); + } + + protected ResponseEntity post(Object body) { + HttpEntity requestEntity = new HttpEntity<>(body); + return rest.postForEntity("/hit", requestEntity, Object.class); + } + + private ResponseEntity makeAndSendRequest(String path) { + HttpEntity requestEntity = new HttpEntity<>(null, defaultHeaders()); + + ResponseEntity responseEntity; + try { + responseEntity = rest.exchange(path, HttpMethod.GET, requestEntity, Object.class); + } catch (HttpStatusCodeException e) { + return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsByteArray()); + } + return prepareResponse(responseEntity); + } + + private HttpHeaders defaultHeaders() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(List.of(MediaType.APPLICATION_JSON)); + return headers; + } + + private static ResponseEntity prepareResponse(ResponseEntity 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(); + } +} \ No newline at end of file diff --git a/stat-svc/stat-dto/pom.xml b/stat-svc/stat-dto/pom.xml new file mode 100644 index 0000000..4067fff --- /dev/null +++ b/stat-svc/stat-dto/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + ru.practicum + explore-with-me + 0.0.1-SNAPSHOT + ../../pom.xml + + + stat-dto + + + 22 + 22 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.projectlombok + lombok + true + + + \ No newline at end of file diff --git a/stat-svc/stat-dto/src/main/java/ru/practicum/stat/EndpointHitCreateDto.java b/stat-svc/stat-dto/src/main/java/ru/practicum/stat/EndpointHitCreateDto.java new file mode 100644 index 0000000..064d5df --- /dev/null +++ b/stat-svc/stat-dto/src/main/java/ru/practicum/stat/EndpointHitCreateDto.java @@ -0,0 +1,24 @@ +package ru.practicum.stat; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; + +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +public class EndpointHitCreateDto { + String app; + String uri; + String ip; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime timestamp; +} diff --git a/stat-svc/stat-dto/src/main/java/ru/practicum/stat/EndpointHitDto.java b/stat-svc/stat-dto/src/main/java/ru/practicum/stat/EndpointHitDto.java new file mode 100644 index 0000000..d137970 --- /dev/null +++ b/stat-svc/stat-dto/src/main/java/ru/practicum/stat/EndpointHitDto.java @@ -0,0 +1,19 @@ +package ru.practicum.stat; + +import lombok.*; +import lombok.experimental.FieldDefaults; + +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +public class EndpointHitDto { + Long id; + String app; + String uri; + String ip; + LocalDateTime timestamp; +} \ No newline at end of file diff --git a/stat-svc/stat-dto/src/main/java/ru/practicum/stat/ViewStatsDto.java b/stat-svc/stat-dto/src/main/java/ru/practicum/stat/ViewStatsDto.java new file mode 100644 index 0000000..ccb3791 --- /dev/null +++ b/stat-svc/stat-dto/src/main/java/ru/practicum/stat/ViewStatsDto.java @@ -0,0 +1,15 @@ +package ru.practicum.stat; + +import lombok.*; +import lombok.experimental.FieldDefaults; + +@FieldDefaults(level = AccessLevel.PRIVATE) +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ViewStatsDto { + String app; + String uri; + Long hits; +} \ No newline at end of file diff --git a/stat-svc/stat-server/Dockerfile b/stat-svc/stat-server/Dockerfile new file mode 100644 index 0000000..0ff1817 --- /dev/null +++ b/stat-svc/stat-server/Dockerfile @@ -0,0 +1,5 @@ +FROM eclipse-temurin:21-jre-jammy +VOLUME /tmp +ARG JAR_FILE=target/*.jar +COPY ${JAR_FILE} app.jar +ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] \ No newline at end of file diff --git a/stat-svc/stat-server/pom.xml b/stat-svc/stat-server/pom.xml new file mode 100644 index 0000000..43c4feb --- /dev/null +++ b/stat-svc/stat-server/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + ru.practicum + explore-with-me + 0.0.1-SNAPSHOT + ../../pom.xml + + + stat-server + + + 22 + 22 + UTF-8 + + + + + ru.practicum + stat-dto + 0.0.1-SNAPSHOT + compile + + + + org.postgresql + postgresql + runtime + + + + com.h2database + h2 + runtime + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.projectlombok + lombok + true + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/EndpointHitRepository.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/EndpointHitRepository.java new file mode 100644 index 0000000..92e3808 --- /dev/null +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/EndpointHitRepository.java @@ -0,0 +1,42 @@ +package ru.practicum.stat; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import ru.practicum.stat.model.EndpointHit; +import ru.practicum.stat.model.ViewStats; + +import java.time.LocalDateTime; +import java.util.List; + +public interface EndpointHitRepository extends JpaRepository { + + @Query("SELECT new ru.practicum.stat.model.ViewStats(e.app, e.uri, COUNT(DISTINCT e.ip)) " + + "FROM EndpointHit e " + + "WHERE e.timestamp BETWEEN ?1 AND ?2 " + + "AND e.uri IN (?3) " + + "GROUP BY e.app, e.uri " + + "ORDER BY COUNT(DISTINCT e.ip) DESC") + List findStatsUniqueIp(LocalDateTime start, LocalDateTime end, List uris); + + @Query("SELECT new ru.practicum.stat.model.ViewStats(e.app, e.uri, COUNT(DISTINCT e.ip)) " + + "FROM EndpointHit e " + + "WHERE e.timestamp BETWEEN ?1 AND ?2 " + + "GROUP BY e.app, e.uri " + + "ORDER BY COUNT(DISTINCT e.ip) DESC") + List findStatsUniqueIpAllUris(LocalDateTime start, LocalDateTime end); + + @Query("SELECT new ru.practicum.stat.model.ViewStats(e.app, e.uri, COUNT(e.ip)) " + + "FROM EndpointHit e " + + "WHERE e.timestamp BETWEEN ?1 AND ?2 " + + "AND e.uri IN (?3) " + + "GROUP BY e.app, e.uri " + + "ORDER BY COUNT(e.ip) DESC") + List findStats(LocalDateTime start, LocalDateTime end, List uris); + + @Query("SELECT new ru.practicum.stat.model.ViewStats(e.app, e.uri, COUNT(e.ip)) " + + "FROM EndpointHit e " + + "WHERE e.timestamp BETWEEN ?1 AND ?2 " + + "GROUP BY e.app, e.uri " + + "ORDER BY COUNT(e.ip) DESC") + List findStatsAllUris(LocalDateTime start, LocalDateTime end); +} \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/StatisticsServer.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/StatisticsServer.java new file mode 100644 index 0000000..ae13c26 --- /dev/null +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/StatisticsServer.java @@ -0,0 +1,11 @@ +package ru.practicum.stat; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class StatisticsServer { + public static void main(String[] args) { + SpringApplication.run(StatisticsServer.class, args); + } +} \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/controller/StatsController.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/controller/StatsController.java new file mode 100644 index 0000000..2f2d525 --- /dev/null +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/controller/StatsController.java @@ -0,0 +1,38 @@ +package ru.practicum.stat.controller; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.web.bind.annotation.*; +import ru.practicum.stat.EndpointHitCreateDto; +import ru.practicum.stat.EndpointHitDto; +import ru.practicum.stat.ViewStatsDto; +import ru.practicum.stat.service.StatisticsService; + +import java.time.LocalDateTime; +import java.util.List; + +@RestController +@RequestMapping +@Slf4j +@RequiredArgsConstructor +public class StatsController { + + private final StatisticsService statisticsService; + + @PostMapping("/hit") + public EndpointHitDto create(@RequestBody EndpointHitCreateDto endpoint) { + log.info("POST запрос на создание нового EndpointHit "); + return statisticsService.create(endpoint); + } + + @GetMapping("/stats") + public List getStats( + @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime start, + @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime end, + @RequestParam(required = false) List uris, + @RequestParam(defaultValue = "false") Boolean unique) { + log.info("GET запрос на получение статистики "); + return statisticsService.getStats(start, end, uris, unique); + } +} \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/exception/ErrorHandler.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/exception/ErrorHandler.java new file mode 100644 index 0000000..29b1635 --- /dev/null +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/exception/ErrorHandler.java @@ -0,0 +1,18 @@ +package ru.practicum.stat.exception; + +import jakarta.validation.ConstraintViolationException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import static org.springframework.http.HttpStatus.BAD_REQUEST; + +@RestControllerAdvice +public class ErrorHandler { + + @ExceptionHandler(ConstraintViolationException.class) + @ResponseStatus(BAD_REQUEST) + public ErrorResponse handleConstraintViolationException(ConstraintViolationException ex) { + return new ErrorResponse("BAD_REQUEST", ex.getMessage()); + } +} \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/exception/ErrorResponse.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/exception/ErrorResponse.java new file mode 100644 index 0000000..3b59b5f --- /dev/null +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/exception/ErrorResponse.java @@ -0,0 +1,11 @@ +package ru.practicum.stat.exception; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class ErrorResponse { + private final String error; + private final String message; +} \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/mapper/EndpointHitMapper.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/mapper/EndpointHitMapper.java new file mode 100644 index 0000000..9f88ca2 --- /dev/null +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/mapper/EndpointHitMapper.java @@ -0,0 +1,27 @@ +package ru.practicum.stat.mapper; + +import ru.practicum.stat.EndpointHitCreateDto; +import ru.practicum.stat.EndpointHitDto; +import ru.practicum.stat.model.EndpointHit; + +public class EndpointHitMapper { + + public static EndpointHit toEndpointHitFromCreateDto(EndpointHitCreateDto dto) { + return EndpointHit.builder() + .app(dto.getApp()) + .uri(dto.getUri()) + .ip(dto.getIp()) + .timestamp(dto.getTimestamp()) + .build(); + } + + public static EndpointHitDto toEndpointHitDto(EndpointHit endpointHit) { + return EndpointHitDto.builder() + .id(endpointHit.getId()) + .app(endpointHit.getApp()) + .uri(endpointHit.getUri()) + .ip(endpointHit.getIp()) + .timestamp(endpointHit.getTimestamp()) + .build(); + } +} \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/mapper/ViewStatsMapper.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/mapper/ViewStatsMapper.java new file mode 100644 index 0000000..e45ee9f --- /dev/null +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/mapper/ViewStatsMapper.java @@ -0,0 +1,15 @@ +package ru.practicum.stat.mapper; + +import ru.practicum.stat.ViewStatsDto; +import ru.practicum.stat.model.ViewStats; + +public class ViewStatsMapper { + + public static ViewStatsDto toViewStatsDto(ViewStats viewStats) { + return ViewStatsDto.builder() + .app(viewStats.getApp()) + .uri(viewStats.getUri()) + .hits(viewStats.getHits()) + .build(); + } +} \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/model/EndpointHit.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/model/EndpointHit.java new file mode 100644 index 0000000..cdcf339 --- /dev/null +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/model/EndpointHit.java @@ -0,0 +1,28 @@ +package ru.practicum.stat.model; + +import jakarta.persistence.*; +import lombok.*; +import lombok.experimental.FieldDefaults; + +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "endpoint") +@FieldDefaults(level = AccessLevel.PRIVATE) +public class EndpointHit { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + Long id; + @Column(nullable = false) + String app; + @Column(nullable = false) + String uri; + @Column(nullable = false) + String ip; + @Column(name = "created", nullable = false) + LocalDateTime timestamp; +} \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/model/ViewStats.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/model/ViewStats.java new file mode 100644 index 0000000..a806a39 --- /dev/null +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/model/ViewStats.java @@ -0,0 +1,15 @@ +package ru.practicum.stat.model; + +import lombok.*; +import lombok.experimental.FieldDefaults; + +@FieldDefaults(level = AccessLevel.PRIVATE) +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ViewStats { + String app; + String uri; + Long hits; +} \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsService.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsService.java new file mode 100644 index 0000000..75cd937 --- /dev/null +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsService.java @@ -0,0 +1,14 @@ +package ru.practicum.stat.service; + +import ru.practicum.stat.EndpointHitCreateDto; +import ru.practicum.stat.EndpointHitDto; +import ru.practicum.stat.ViewStatsDto; + +import java.time.LocalDateTime; +import java.util.List; + +public interface StatisticsService { + EndpointHitDto create(EndpointHitCreateDto endpoint); + + List getStats(LocalDateTime start, LocalDateTime end, List uris, Boolean unique); +} diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsServiceImpl.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsServiceImpl.java new file mode 100644 index 0000000..1534dc5 --- /dev/null +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsServiceImpl.java @@ -0,0 +1,61 @@ +package ru.practicum.stat.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.stat.EndpointHitRepository; +import ru.practicum.stat.EndpointHitCreateDto; +import ru.practicum.stat.EndpointHitDto; +import ru.practicum.stat.ViewStatsDto; +import ru.practicum.stat.mapper.EndpointHitMapper; +import ru.practicum.stat.mapper.ViewStatsMapper; +import ru.practicum.stat.model.EndpointHit; +import ru.practicum.stat.model.ViewStats; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@Slf4j +@Transactional +public class StatisticsServiceImpl implements StatisticsService { + + private final EndpointHitRepository endpointHitRepository; + + @Override + public EndpointHitDto create(EndpointHitCreateDto endpointHitCreateDto) { + log.info("Создание EndpointHit с данными: {}", endpointHitCreateDto); + EndpointHit hit = EndpointHitMapper.toEndpointHitFromCreateDto(endpointHitCreateDto); + EndpointHit createdHit = endpointHitRepository.save(hit); + return EndpointHitMapper.toEndpointHitDto(createdHit); + } + + @Transactional(readOnly = true) + @Override + public List getStats(LocalDateTime start, LocalDateTime end, List uris, Boolean unique) { + log.info("Получение статистики с start={}, end={}, uris={}, unique={}", start, end, uris, unique); + + List viewStats; + if (unique) { + if (uris != null && !uris.isEmpty()) { + viewStats = endpointHitRepository.findStatsUniqueIp(start, end, uris); + } else { + viewStats = endpointHitRepository.findStatsUniqueIpAllUris(start, end); + } + } else { + if (uris != null && !uris.isEmpty()) { + viewStats = endpointHitRepository.findStats(start, end, uris); + } else { + viewStats = endpointHitRepository.findStatsAllUris(start, end); + } + } + log.info("Получена статистика: {}", viewStats); + + return viewStats != null ? viewStats.stream() + .map(ViewStatsMapper::toViewStatsDto) + .collect(Collectors.toList()) : List.of(); + } +} diff --git a/stat-svc/stat-server/src/main/resources/application-h2.properties b/stat-svc/stat-server/src/main/resources/application-h2.properties new file mode 100644 index 0000000..10b8a91 --- /dev/null +++ b/stat-svc/stat-server/src/main/resources/application-h2.properties @@ -0,0 +1,5 @@ +spring.config.activate.on-profile=h2 +spring.datasource.driverClassName = org.h2.Driver +spring.datasource.url = jdbc:h2:file:./db/statdb +spring.datasource.username = admin +spring.datasource.password = admin \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/resources/application-postgres.properties b/stat-svc/stat-server/src/main/resources/application-postgres.properties new file mode 100644 index 0000000..b398ca7 --- /dev/null +++ b/stat-svc/stat-server/src/main/resources/application-postgres.properties @@ -0,0 +1,5 @@ +spring.config.activate.on-profile=postgres +spring.datasource.driverClassName = org.postgresql.Driver +spring.datasource.url = jdbc:postgresql://localhost:5432/statdb +spring.datasource.username = admin +spring.datasource.password = admin \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/resources/application.properties b/stat-svc/stat-server/src/main/resources/application.properties new file mode 100644 index 0000000..7bf847d --- /dev/null +++ b/stat-svc/stat-server/src/main/resources/application.properties @@ -0,0 +1,10 @@ +server.port=9090 + +spring.jpa.hibernate.ddl-auto=none +spring.jpa.properties.hibernate.format_sql=true +spring.sql.init.mode=always + +logging.level.org.springframework.orm.jpa=INFO +logging.level.org.springframework.transaction=INFO +logging.level.org.springframework.transaction.interceptor=TRACE +logging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUG \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/resources/schema.sql b/stat-svc/stat-server/src/main/resources/schema.sql new file mode 100644 index 0000000..406911f --- /dev/null +++ b/stat-svc/stat-server/src/main/resources/schema.sql @@ -0,0 +1,9 @@ +DROP TABLE IF EXISTS endpoint CASCADE; + +CREATE TABLE IF NOT EXISTS endpoint( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + app VARCHAR(255) NOT NULL, + uri VARCHAR(255) NOT NULL, + ip VARCHAR(15) NOT NULL, + created TIMESTAMP WITHOUT TIME ZONE NOT NULL +); \ No newline at end of file From cf8883e21568e5cc4ea7260d16869f552443fd15 Mon Sep 17 00:00:00 2001 From: pavelrk97 Date: Fri, 5 Sep 2025 00:41:24 +0300 Subject: [PATCH 2/9] stat_svc_all_postman --- docker-compose.yml | 49 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index be96142..8f0e3a1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,59 @@ services: - stats-server: + stat-server: + build: + context: ./stat-svc/stat-server + image: stat-server + container_name: stat-server ports: - "9090:9090" + depends_on: + - statdb + environment: + - SPRING_DATASOURCE_URL=jdbc:postgresql://statdb:5432/statdb + - SPRING_DATASOURCE_USERNAME=admin + - SPRING_DATASOURCE_PASSWORD=admin - stats-db: + statdb: image: postgres:16.1 + container_name: statdb + ports: + - "6541:5432" + environment: + - POSTGRES_PASSWORD=admin + - POSTGRES_USER=admin + - POSTGRES_DB=statdb + healthcheck: + test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER + timeout: 5s + interval: 5s + retries: 10 ewm-service: + build: + context: ./ewm-main-svc + image: ewm-service + container_name: ewm-service + environment: + SPRING_DATASOURCE_URL: jdbc:postgresql://ewm-db:5432/ewm-db + SPRING_DATASOURCE_USERNAME: admin + SPRING_DATASOURCE_PASSWORD: admin ports: - "8080:8080" + depends_on: + - stat-server + - ewm-db ewm-db: image: postgres:16.1 + container_name: ewm-db + ports: + - "6542:5432" + environment: + - POSTGRES_DB=ewm-db + - POSTGRES_USER=admin + - POSTGRES_PASSWORD=admin + healthcheck: + test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER + timeout: 5s + interval: 5s + retries: 10 \ No newline at end of file From 742268745ce587dcbadd91719fcf3df03280620a Mon Sep 17 00:00:00 2001 From: pavelrk97 Date: Mon, 8 Sep 2025 00:23:12 +0300 Subject: [PATCH 3/9] =?UTF-8?q?stat=5Fsvc=5Fall=5Fpostman=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=94=D0=A2?= =?UTF-8?q?=D0=9E=20getStats=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=87=D1=82=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F.=20=D0=94=D1=82=D0=BE=20=D1=81=D0=BE=D0=B1=D0=B8?= =?UTF-8?q?=D1=80=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D0=B2=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/practicum/stat/StatsRequestDto.java | 19 +++++++++++++++ .../stat/controller/StatsController.java | 14 +++++++++-- .../stat/service/StatisticsService.java | 4 ++-- .../stat/service/StatisticsServiceImpl.java | 23 ++++++++----------- 4 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 stat-svc/stat-dto/src/main/java/ru/practicum/stat/StatsRequestDto.java diff --git a/stat-svc/stat-dto/src/main/java/ru/practicum/stat/StatsRequestDto.java b/stat-svc/stat-dto/src/main/java/ru/practicum/stat/StatsRequestDto.java new file mode 100644 index 0000000..a7b11c1 --- /dev/null +++ b/stat-svc/stat-dto/src/main/java/ru/practicum/stat/StatsRequestDto.java @@ -0,0 +1,19 @@ +package ru.practicum.stat; + +import lombok.*; +import lombok.experimental.FieldDefaults; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +public class StatsRequestDto { + LocalDateTime start; + LocalDateTime end; + List uris; + Boolean unique; +} diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/controller/StatsController.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/controller/StatsController.java index 2f2d525..aa92358 100644 --- a/stat-svc/stat-server/src/main/java/ru/practicum/stat/controller/StatsController.java +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/controller/StatsController.java @@ -6,6 +6,7 @@ import org.springframework.web.bind.annotation.*; import ru.practicum.stat.EndpointHitCreateDto; import ru.practicum.stat.EndpointHitDto; +import ru.practicum.stat.StatsRequestDto; import ru.practicum.stat.ViewStatsDto; import ru.practicum.stat.service.StatisticsService; @@ -32,7 +33,16 @@ public List getStats( @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime end, @RequestParam(required = false) List uris, @RequestParam(defaultValue = "false") Boolean unique) { - log.info("GET запрос на получение статистики "); - return statisticsService.getStats(start, end, uris, unique); + + log.info("GET запрос на получение статистики: start={}, end={}, uris={}, unique={}", start, end, uris, unique); + + StatsRequestDto request = StatsRequestDto.builder() + .start(start) + .end(end) + .uris(uris) + .unique(unique) + .build(); + + return statisticsService.getStats(request); } } \ No newline at end of file diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsService.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsService.java index 75cd937..daa946a 100644 --- a/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsService.java +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsService.java @@ -2,13 +2,13 @@ import ru.practicum.stat.EndpointHitCreateDto; import ru.practicum.stat.EndpointHitDto; +import ru.practicum.stat.StatsRequestDto; import ru.practicum.stat.ViewStatsDto; -import java.time.LocalDateTime; import java.util.List; public interface StatisticsService { EndpointHitDto create(EndpointHitCreateDto endpoint); - List getStats(LocalDateTime start, LocalDateTime end, List uris, Boolean unique); + List getStats(StatsRequestDto statsRequestDto); } diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsServiceImpl.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsServiceImpl.java index 1534dc5..4a679c7 100644 --- a/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsServiceImpl.java +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsServiceImpl.java @@ -4,10 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import ru.practicum.stat.EndpointHitRepository; -import ru.practicum.stat.EndpointHitCreateDto; -import ru.practicum.stat.EndpointHitDto; -import ru.practicum.stat.ViewStatsDto; +import ru.practicum.stat.*; import ru.practicum.stat.mapper.EndpointHitMapper; import ru.practicum.stat.mapper.ViewStatsMapper; import ru.practicum.stat.model.EndpointHit; @@ -35,21 +32,21 @@ public EndpointHitDto create(EndpointHitCreateDto endpointHitCreateDto) { @Transactional(readOnly = true) @Override - public List getStats(LocalDateTime start, LocalDateTime end, List uris, Boolean unique) { - log.info("Получение статистики с start={}, end={}, uris={}, unique={}", start, end, uris, unique); + public List getStats(StatsRequestDto request) { + log.info("Получение статистики: {}", request); List viewStats; - if (unique) { - if (uris != null && !uris.isEmpty()) { - viewStats = endpointHitRepository.findStatsUniqueIp(start, end, uris); + if (Boolean.TRUE.equals(request.getUnique())) { + if (request.getUris() != null && !request.getUris().isEmpty()) { + viewStats = endpointHitRepository.findStatsUniqueIp(request.getStart(), request.getEnd(), request.getUris()); } else { - viewStats = endpointHitRepository.findStatsUniqueIpAllUris(start, end); + viewStats = endpointHitRepository.findStatsUniqueIpAllUris(request.getStart(), request.getEnd()); } } else { - if (uris != null && !uris.isEmpty()) { - viewStats = endpointHitRepository.findStats(start, end, uris); + if (request.getUris() != null && !request.getUris().isEmpty()) { + viewStats = endpointHitRepository.findStats(request.getStart(), request.getEnd(), request.getUris()); } else { - viewStats = endpointHitRepository.findStatsAllUris(start, end); + viewStats = endpointHitRepository.findStatsAllUris(request.getStart(), request.getEnd()); } } log.info("Получена статистика: {}", viewStats); From 43828c315d148e875beeea3c0bbb9d4d31f8b915 Mon Sep 17 00:00:00 2001 From: pavelrk97 Date: Mon, 8 Sep 2025 00:42:08 +0300 Subject: [PATCH 4/9] =?UTF-8?q?stat=5Fsvc=5Fall=5Fpostman=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=94=D0=A2?= =?UTF-8?q?=D0=9E=20getStats=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=87=D1=82=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F.=20=D0=94=D1=82=D0=BE=20=D1=81=D0=BE=D0=B1=D0=B8?= =?UTF-8?q?=D1=80=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D0=B2=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 60 +--------------------------------------------- 1 file changed, 1 insertion(+), 59 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8f0e3a1..d800886 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,59 +1 @@ -services: - stat-server: - build: - context: ./stat-svc/stat-server - image: stat-server - container_name: stat-server - ports: - - "9090:9090" - depends_on: - - statdb - environment: - - SPRING_DATASOURCE_URL=jdbc:postgresql://statdb:5432/statdb - - SPRING_DATASOURCE_USERNAME=admin - - SPRING_DATASOURCE_PASSWORD=admin - - statdb: - image: postgres:16.1 - container_name: statdb - ports: - - "6541:5432" - environment: - - POSTGRES_PASSWORD=admin - - POSTGRES_USER=admin - - POSTGRES_DB=statdb - healthcheck: - test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER - timeout: 5s - interval: 5s - retries: 10 - - ewm-service: - build: - context: ./ewm-main-svc - image: ewm-service - container_name: ewm-service - environment: - SPRING_DATASOURCE_URL: jdbc:postgresql://ewm-db:5432/ewm-db - SPRING_DATASOURCE_USERNAME: admin - SPRING_DATASOURCE_PASSWORD: admin - ports: - - "8080:8080" - depends_on: - - stat-server - - ewm-db - - ewm-db: - image: postgres:16.1 - container_name: ewm-db - ports: - - "6542:5432" - environment: - - POSTGRES_DB=ewm-db - - POSTGRES_USER=admin - - POSTGRES_PASSWORD=admin - healthcheck: - test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER - timeout: 5s - interval: 5s - retries: 10 \ No newline at end of file +123 \ No newline at end of file From 08b8d4560aac53521a3c1105d5a16911c27195f2 Mon Sep 17 00:00:00 2001 From: pavelrk97 Date: Mon, 8 Sep 2025 00:42:22 +0300 Subject: [PATCH 5/9] =?UTF-8?q?stat=5Fsvc=5Fall=5Fpostman=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=94=D0=A2?= =?UTF-8?q?=D0=9E=20getStats=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=87=D1=82=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F.=20=D0=94=D1=82=D0=BE=20=D1=81=D0=BE=D0=B1=D0=B8?= =?UTF-8?q?=D1=80=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D0=B2=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 60 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index d800886..8f0e3a1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1 +1,59 @@ -123 \ No newline at end of file +services: + stat-server: + build: + context: ./stat-svc/stat-server + image: stat-server + container_name: stat-server + ports: + - "9090:9090" + depends_on: + - statdb + environment: + - SPRING_DATASOURCE_URL=jdbc:postgresql://statdb:5432/statdb + - SPRING_DATASOURCE_USERNAME=admin + - SPRING_DATASOURCE_PASSWORD=admin + + statdb: + image: postgres:16.1 + container_name: statdb + ports: + - "6541:5432" + environment: + - POSTGRES_PASSWORD=admin + - POSTGRES_USER=admin + - POSTGRES_DB=statdb + healthcheck: + test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER + timeout: 5s + interval: 5s + retries: 10 + + ewm-service: + build: + context: ./ewm-main-svc + image: ewm-service + container_name: ewm-service + environment: + SPRING_DATASOURCE_URL: jdbc:postgresql://ewm-db:5432/ewm-db + SPRING_DATASOURCE_USERNAME: admin + SPRING_DATASOURCE_PASSWORD: admin + ports: + - "8080:8080" + depends_on: + - stat-server + - ewm-db + + ewm-db: + image: postgres:16.1 + container_name: ewm-db + ports: + - "6542:5432" + environment: + - POSTGRES_DB=ewm-db + - POSTGRES_USER=admin + - POSTGRES_PASSWORD=admin + healthcheck: + test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER + timeout: 5s + interval: 5s + retries: 10 \ No newline at end of file From 1911a35406c4d3c2afd6d0042c48ed1a471c8405 Mon Sep 17 00:00:00 2001 From: pavelrk97 Date: Mon, 8 Sep 2025 01:01:14 +0300 Subject: [PATCH 6/9] =?UTF-8?q?stat=5Fsvc=5Fall=5Fpostman=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=94=D0=A2?= =?UTF-8?q?=D0=9E=20getStats=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=87=D1=82=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F.=20=D0=94=D1=82=D0=BE=20=D1=81=D0=BE=D0=B1=D0=B8?= =?UTF-8?q?=D1=80=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D0=B2=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 4 ++-- .../java/ru/practicum/stat/service/StatisticsServiceImpl.java | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8f0e3a1..e3e2fe8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,8 @@ services: - stat-server: + stats-server: build: context: ./stat-svc/stat-server - image: stat-server + image: stats-server container_name: stat-server ports: - "9090:9090" diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsServiceImpl.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsServiceImpl.java index 4a679c7..d6729b2 100644 --- a/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsServiceImpl.java +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/service/StatisticsServiceImpl.java @@ -10,7 +10,6 @@ import ru.practicum.stat.model.EndpointHit; import ru.practicum.stat.model.ViewStats; -import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; From 2f3495421bb297509e764304aa924285d44ef5d6 Mon Sep 17 00:00:00 2001 From: pavelrk97 Date: Mon, 8 Sep 2025 01:05:45 +0300 Subject: [PATCH 7/9] =?UTF-8?q?stat=5Fsvc=5Fall=5Fpostman=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=94=D0=A2?= =?UTF-8?q?=D0=9E=20getStats=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=87=D1=82=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F.=20=D0=94=D1=82=D0=BE=20=D1=81=D0=BE=D0=B1=D0=B8?= =?UTF-8?q?=D1=80=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D0=B2=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stat-svc/stat-server/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stat-svc/stat-server/pom.xml b/stat-svc/stat-server/pom.xml index 43c4feb..d5b0654 100644 --- a/stat-svc/stat-server/pom.xml +++ b/stat-svc/stat-server/pom.xml @@ -10,7 +10,7 @@ ../../pom.xml - stat-server + stats-server 22 From 1e256a2e15b02ea3f615ea022b01da538ce334ef Mon Sep 17 00:00:00 2001 From: pavelrk97 Date: Mon, 8 Sep 2025 01:10:03 +0300 Subject: [PATCH 8/9] =?UTF-8?q?stat=5Fsvc=5Fall=5Fpostman=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=94=D0=A2?= =?UTF-8?q?=D0=9E=20getStats=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=87=D1=82=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F.=20=D0=94=D1=82=D0=BE=20=D1=81=D0=BE=D0=B1=D0=B8?= =?UTF-8?q?=D1=80=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D0=B2=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index e3e2fe8..f3b78d9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,7 +40,7 @@ services: ports: - "8080:8080" depends_on: - - stat-server + - stats-server - ewm-db ewm-db: From a91140f43e2681315d45b3d37747413c3f5a6407 Mon Sep 17 00:00:00 2001 From: pavelrk97 Date: Mon, 8 Sep 2025 01:25:19 +0300 Subject: [PATCH 9/9] =?UTF-8?q?stat=5Fsvc=5Fall=5Fpostman=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=94=D0=A2?= =?UTF-8?q?=D0=9E=20getStats=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=87=D1=82=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F.=20=D0=94=D1=82=D0=BE=20=D1=81=D0=BE=D0=B1=D0=B8?= =?UTF-8?q?=D1=80=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D0=B2=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/ru/practicum/stat/exception/ErrorHandler.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stat-svc/stat-server/src/main/java/ru/practicum/stat/exception/ErrorHandler.java b/stat-svc/stat-server/src/main/java/ru/practicum/stat/exception/ErrorHandler.java index 29b1635..eef7442 100644 --- a/stat-svc/stat-server/src/main/java/ru/practicum/stat/exception/ErrorHandler.java +++ b/stat-svc/stat-server/src/main/java/ru/practicum/stat/exception/ErrorHandler.java @@ -4,15 +4,19 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; +import lombok.extern.slf4j.Slf4j; import static org.springframework.http.HttpStatus.BAD_REQUEST; +@Slf4j @RestControllerAdvice public class ErrorHandler { @ExceptionHandler(ConstraintViolationException.class) @ResponseStatus(BAD_REQUEST) public ErrorResponse handleConstraintViolationException(ConstraintViolationException ex) { + log.warn("Constraint violation: {}", ex.getMessage(), ex); + return new ErrorResponse("BAD_REQUEST", ex.getMessage()); } } \ No newline at end of file