From e30f3a13915b96c724d771c603734a8fd5219087 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Thu, 17 Jul 2025 16:00:23 +0500 Subject: [PATCH 1/6] work stat-server --- docker-compose.yml | 32 +++++++ main-service/Dockerfile | 5 ++ main-service/pom.xml | 87 ++++++++++++++++++ .../main/java/ewm/MainServiceApplication.java | 11 +++ pom.xml | 9 +- stats/pom.xml | 21 +++++ stats/stats-client/pom.xml | 21 +++++ stats/stats-dto/pom.xml | 71 +++++++++++++++ .../src/main/java/dto/CreateDto.java | 32 +++++++ .../src/main/java/dto/ViewStatsDto.java | 18 ++++ stats/stats-server/Dockerfile | 5 ++ stats/stats-server/pom.xml | 88 +++++++++++++++++++ .../src/main/java/ewm/StatApplication.java | 12 +++ .../ewm/exception/BadRequestException.java | 7 ++ .../java/ewm/exception/ConflictException.java | 8 ++ .../main/java/ewm/exception/ErrorHandler.java | 39 ++++++++ .../java/ewm/exception/ErrorResponse.java | 19 ++++ .../InternalServerErrorException.java | 7 ++ .../java/ewm/exception/NotFoundException.java | 8 ++ .../src/main/java/ewm/stat/EndpointHit.java | 34 +++++++ .../java/ewm/stat/EndpointHitController.java | 33 +++++++ .../main/java/ewm/stat/EndpointHitMapper.java | 19 ++++ .../java/ewm/stat/EndpointHitRepository.java | 38 ++++++++ .../ewm/stat/service/EndpointHitService.java | 14 +++ .../stat/service/EndpointHitServiceImpl.java | 38 ++++++++ .../src/main/resources/application.properties | 21 +++++ .../src/main/resources/schema.sql | 8 ++ 27 files changed, 704 insertions(+), 1 deletion(-) create mode 100644 main-service/Dockerfile create mode 100644 main-service/pom.xml create mode 100644 main-service/src/main/java/ewm/MainServiceApplication.java create mode 100644 stats/pom.xml create mode 100644 stats/stats-client/pom.xml create mode 100644 stats/stats-dto/pom.xml create mode 100644 stats/stats-dto/src/main/java/dto/CreateDto.java create mode 100644 stats/stats-dto/src/main/java/dto/ViewStatsDto.java create mode 100644 stats/stats-server/Dockerfile create mode 100644 stats/stats-server/pom.xml create mode 100644 stats/stats-server/src/main/java/ewm/StatApplication.java create mode 100644 stats/stats-server/src/main/java/ewm/exception/BadRequestException.java create mode 100644 stats/stats-server/src/main/java/ewm/exception/ConflictException.java create mode 100644 stats/stats-server/src/main/java/ewm/exception/ErrorHandler.java create mode 100644 stats/stats-server/src/main/java/ewm/exception/ErrorResponse.java create mode 100644 stats/stats-server/src/main/java/ewm/exception/InternalServerErrorException.java create mode 100644 stats/stats-server/src/main/java/ewm/exception/NotFoundException.java create mode 100644 stats/stats-server/src/main/java/ewm/stat/EndpointHit.java create mode 100644 stats/stats-server/src/main/java/ewm/stat/EndpointHitController.java create mode 100644 stats/stats-server/src/main/java/ewm/stat/EndpointHitMapper.java create mode 100644 stats/stats-server/src/main/java/ewm/stat/EndpointHitRepository.java create mode 100644 stats/stats-server/src/main/java/ewm/stat/service/EndpointHitService.java create mode 100644 stats/stats-server/src/main/java/ewm/stat/service/EndpointHitServiceImpl.java create mode 100644 stats/stats-server/src/main/resources/application.properties create mode 100644 stats/stats-server/src/main/resources/schema.sql diff --git a/docker-compose.yml b/docker-compose.yml index be96142..883ab4e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,46 @@ +version: '3.8' + services: stats-server: + build: stats/stats-server + container_name: stat-server ports: - "9090:9090" + environment: + - SPRING_DATASOURCE_URL=jdbc:postgresql://stats-db:5432/ewm-stats + - SPRING_DATASOURCE_USERNAME=stat + - SPRING_DATASOURCE_PASSWORD=stat + depends_on: + - stats-db stats-db: image: postgres:16.1 + container_name: postgres-ewm-stats-db + ports: + - "6542:5432" + environment: + - POSTGRES_PASSWORD=stat + - POSTGRES_USER=stat + - POSTGRES_DB=ewm-stats ewm-service: + build: main-service ports: - "8080:8080" + environment: + - CLIENT_URL=http://stats-server:9090 + - SPRING_DATASOURCE_URL=jdbc:postgresql://ewm-db:5432/ewm-main + - SPRING_DATASOURCE_USERNAME=main + - SPRING_DATASOURCE_PASSWORD=main + depends_on: + - ewm-db ewm-db: image: postgres:16.1 + container_name: postgres-ewm-main-service-db + ports: + - "7542:5432" + environment: + - POSTGRES_PASSWORD=main + - POSTGRES_USER=main + - POSTGRES_DB=ewm-main \ No newline at end of file diff --git a/main-service/Dockerfile b/main-service/Dockerfile new file mode 100644 index 0000000..0ff1817 --- /dev/null +++ b/main-service/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/main-service/pom.xml b/main-service/pom.xml new file mode 100644 index 0000000..dea6df8 --- /dev/null +++ b/main-service/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + + ru.practicum + explore-with-me + 0.0.1-SNAPSHOT + + + main-service + + + 21 + 21 + UTF-8 + + + + + org.zalando + logbook-spring-boot-starter + 3.7.2 + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.postgresql + postgresql + runtime + + + + com.h2database + h2 + runtime + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + ru.practicum + stats-dto + 0.0.1-SNAPSHOT + compile + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/main-service/src/main/java/ewm/MainServiceApplication.java b/main-service/src/main/java/ewm/MainServiceApplication.java new file mode 100644 index 0000000..fce1434 --- /dev/null +++ b/main-service/src/main/java/ewm/MainServiceApplication.java @@ -0,0 +1,11 @@ +package ewm; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MainServiceApplication { + public static void main(String[] args) { + SpringApplication.run(MainServiceApplication.class, args); + } +} diff --git a/pom.xml b/pom.xml index b15acb2..0e74b80 100644 --- a/pom.xml +++ b/pom.xml @@ -11,8 +11,15 @@ Explore With Me + + main-service + stats + stats/stats-client + stats/stats-dto + stats/stats-server + - ru.practicum + ru.practicum explore-with-me 0.0.1-SNAPSHOT pom diff --git a/stats/pom.xml b/stats/pom.xml new file mode 100644 index 0000000..78a227e --- /dev/null +++ b/stats/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + ru.practicum + explore-with-me + 0.0.1-SNAPSHOT + + + + stats + + + 21 + 21 + UTF-8 + + + \ No newline at end of file diff --git a/stats/stats-client/pom.xml b/stats/stats-client/pom.xml new file mode 100644 index 0000000..05bd8e1 --- /dev/null +++ b/stats/stats-client/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + ru.practicum + explore-with-me + 0.0.1-SNAPSHOT + ../../pom.xml + + + stats-client + + + 22 + 22 + UTF-8 + + + \ No newline at end of file diff --git a/stats/stats-dto/pom.xml b/stats/stats-dto/pom.xml new file mode 100644 index 0000000..57a04c2 --- /dev/null +++ b/stats/stats-dto/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + ru.practicum + explore-with-me + 0.0.1-SNAPSHOT + ../../pom.xml + + + stats-dto + + + 22 + 22 + UTF-8 + + + + + org.zalando + logbook-spring-boot-starter + 3.7.2 + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.hibernate.validator + hibernate-validator + + + + org.apache.httpcomponents.client5 + httpclient5 + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + \ No newline at end of file diff --git a/stats/stats-dto/src/main/java/dto/CreateDto.java b/stats/stats-dto/src/main/java/dto/CreateDto.java new file mode 100644 index 0000000..22cbd3f --- /dev/null +++ b/stats/stats-dto/src/main/java/dto/CreateDto.java @@ -0,0 +1,32 @@ +package dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.FutureOrPresent; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Setter +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class CreateDto { + @NotNull + private String app; + + @NotNull + private String uri; + + @NotNull + private String ip; + + @NotNull + @FutureOrPresent + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime timestamp; + +} diff --git a/stats/stats-dto/src/main/java/dto/ViewStatsDto.java b/stats/stats-dto/src/main/java/dto/ViewStatsDto.java new file mode 100644 index 0000000..bdfd1ec --- /dev/null +++ b/stats/stats-dto/src/main/java/dto/ViewStatsDto.java @@ -0,0 +1,18 @@ +package dto; + +import lombok.*; + + +@Getter +@Setter +public class ViewStatsDto { + private String app; + private String uri; + private Long hits; + + public ViewStatsDto(String app, String uri, Long hits) { + this.app = app; + this.uri = uri; + this.hits = hits; + } +} diff --git a/stats/stats-server/Dockerfile b/stats/stats-server/Dockerfile new file mode 100644 index 0000000..0ff1817 --- /dev/null +++ b/stats/stats-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/stats/stats-server/pom.xml b/stats/stats-server/pom.xml new file mode 100644 index 0000000..af87956 --- /dev/null +++ b/stats/stats-server/pom.xml @@ -0,0 +1,88 @@ + + + 4.0.0 + + ru.practicum + explore-with-me + 0.0.1-SNAPSHOT + ../../pom.xml + + + stats-server + + + 21 + 21 + UTF-8 + + + + + org.zalando + logbook-spring-boot-starter + 3.7.2 + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.postgresql + postgresql + runtime + + + + com.h2database + h2 + runtime + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + ru.practicum + stats-dto + 0.0.1-SNAPSHOT + compile + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/stats/stats-server/src/main/java/ewm/StatApplication.java b/stats/stats-server/src/main/java/ewm/StatApplication.java new file mode 100644 index 0000000..30d81c5 --- /dev/null +++ b/stats/stats-server/src/main/java/ewm/StatApplication.java @@ -0,0 +1,12 @@ +package ewm; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class StatApplication { + public static void main(String[] args) { + SpringApplication.run(StatApplication.class, args); + } + +} diff --git a/stats/stats-server/src/main/java/ewm/exception/BadRequestException.java b/stats/stats-server/src/main/java/ewm/exception/BadRequestException.java new file mode 100644 index 0000000..4bf52b6 --- /dev/null +++ b/stats/stats-server/src/main/java/ewm/exception/BadRequestException.java @@ -0,0 +1,7 @@ +package ewm.exception; + +public class BadRequestException extends RuntimeException { + public BadRequestException(String message) { + super(message); + } +} diff --git a/stats/stats-server/src/main/java/ewm/exception/ConflictException.java b/stats/stats-server/src/main/java/ewm/exception/ConflictException.java new file mode 100644 index 0000000..6bcc2f4 --- /dev/null +++ b/stats/stats-server/src/main/java/ewm/exception/ConflictException.java @@ -0,0 +1,8 @@ +package ewm.exception; + +public class ConflictException extends RuntimeException { + public ConflictException(String message) { + super(message); + } +} + diff --git a/stats/stats-server/src/main/java/ewm/exception/ErrorHandler.java b/stats/stats-server/src/main/java/ewm/exception/ErrorHandler.java new file mode 100644 index 0000000..3154594 --- /dev/null +++ b/stats/stats-server/src/main/java/ewm/exception/ErrorHandler.java @@ -0,0 +1,39 @@ +package ewm.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + + +@RestControllerAdvice +public class ErrorHandler { + + @ExceptionHandler + @ResponseStatus(HttpStatus.NOT_FOUND) + public ErrorResponse handleNotFoundException(final NotFoundException e) { + return new ErrorResponse("Error", e.getMessage()); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ErrorResponse handleInternalServerErrorException(final InternalServerErrorException e) { + return new ErrorResponse("Error", e.getMessage()); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.CONFLICT) + public ErrorResponse handleConflictException(final ConflictException e) { + return new ErrorResponse("Error", e.getMessage()); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ErrorResponse handleBadRequestException(final BadRequestException e) { + return new ErrorResponse("Error", e.getMessage()); + } + +} + + + diff --git a/stats/stats-server/src/main/java/ewm/exception/ErrorResponse.java b/stats/stats-server/src/main/java/ewm/exception/ErrorResponse.java new file mode 100644 index 0000000..2fdf34c --- /dev/null +++ b/stats/stats-server/src/main/java/ewm/exception/ErrorResponse.java @@ -0,0 +1,19 @@ +package ewm.exception; + +public class ErrorResponse { + private final String error; + private final String description; + + public ErrorResponse(String error, String description) { + this.error = error; + this.description = description; + } + + public String getError() { + return error; + } + + public String getDescription() { + return description; + } +} \ No newline at end of file diff --git a/stats/stats-server/src/main/java/ewm/exception/InternalServerErrorException.java b/stats/stats-server/src/main/java/ewm/exception/InternalServerErrorException.java new file mode 100644 index 0000000..3164b3a --- /dev/null +++ b/stats/stats-server/src/main/java/ewm/exception/InternalServerErrorException.java @@ -0,0 +1,7 @@ +package ewm.exception; + +public class InternalServerErrorException extends RuntimeException { + public InternalServerErrorException(String message) { + super(message); + } +} diff --git a/stats/stats-server/src/main/java/ewm/exception/NotFoundException.java b/stats/stats-server/src/main/java/ewm/exception/NotFoundException.java new file mode 100644 index 0000000..41ec5e7 --- /dev/null +++ b/stats/stats-server/src/main/java/ewm/exception/NotFoundException.java @@ -0,0 +1,8 @@ +package ewm.exception; + +public class NotFoundException extends RuntimeException { + public NotFoundException(String message) { + super(message); + } +} + diff --git a/stats/stats-server/src/main/java/ewm/stat/EndpointHit.java b/stats/stats-server/src/main/java/ewm/stat/EndpointHit.java new file mode 100644 index 0000000..6ba22d7 --- /dev/null +++ b/stats/stats-server/src/main/java/ewm/stat/EndpointHit.java @@ -0,0 +1,34 @@ +package ewm.stat; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Getter +@Setter +@Entity +@Table(name = "endpoint_hits") +public class EndpointHit { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(nullable = false) + private String app; + + @Column(nullable = false) + private String uri; + + @Column(nullable = false) + private String ip; + + @Column(nullable = false) + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime timestamp; + +} diff --git a/stats/stats-server/src/main/java/ewm/stat/EndpointHitController.java b/stats/stats-server/src/main/java/ewm/stat/EndpointHitController.java new file mode 100644 index 0000000..86af090 --- /dev/null +++ b/stats/stats-server/src/main/java/ewm/stat/EndpointHitController.java @@ -0,0 +1,33 @@ +package ewm.stat; + +import dto.CreateDto; +import dto.ViewStatsDto; +import ewm.stat.service.EndpointHitService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping +public class EndpointHitController { + private final EndpointHitService service; + + @ResponseStatus(HttpStatus.CREATED) + @PostMapping("/hit") + public void create(@RequestBody CreateDto createDto) { + service.create(createDto); + } + + @GetMapping("/stats") + public List getStats(@RequestParam LocalDateTime start, @RequestParam LocalDateTime end, + @RequestParam(required = false) List uris, + @RequestParam(defaultValue = "false") boolean unique) { + return service.getStats(start, end, uris, unique); + + } + +} diff --git a/stats/stats-server/src/main/java/ewm/stat/EndpointHitMapper.java b/stats/stats-server/src/main/java/ewm/stat/EndpointHitMapper.java new file mode 100644 index 0000000..fe03da4 --- /dev/null +++ b/stats/stats-server/src/main/java/ewm/stat/EndpointHitMapper.java @@ -0,0 +1,19 @@ +package ewm.stat; + +import dto.CreateDto; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@RequiredArgsConstructor +@Component +public class EndpointHitMapper { + + public EndpointHit dtoToModel(CreateDto dto) { + return EndpointHit.builder() + .app(dto.getApp()) + .uri(dto.getUri()) + .ip(dto.getIp()) + .timestamp(dto.getTimestamp()) + .build(); + } +} diff --git a/stats/stats-server/src/main/java/ewm/stat/EndpointHitRepository.java b/stats/stats-server/src/main/java/ewm/stat/EndpointHitRepository.java new file mode 100644 index 0000000..67ba146 --- /dev/null +++ b/stats/stats-server/src/main/java/ewm/stat/EndpointHitRepository.java @@ -0,0 +1,38 @@ +package ewm.stat; + +import dto.ViewStatsDto; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.time.LocalDateTime; +import java.util.List; + +public interface EndpointHitRepository extends JpaRepository { + + @Query("SELECT new dto.ViewStatsDto(e.app, e.uri, COUNT(e.ip) as hits) " + + "FROM EndpointHit e " + + "WHERE e.timestamp BETWEEN :start AND :end " + + "AND (:uris IS NULL OR e.uri IN :uris) " + + "GROUP BY e.app, e.uri " + + "ORDER BY COUNT(e.ip) DESC") + List getStats( + @Param("start") LocalDateTime start, + @Param("end") LocalDateTime end, + @Param("uris") List uris); + + @Query("SELECT new dto.ViewStatsDto(e.app, e.uri, COUNT(DISTINCT e.ip) as hits) " + + "FROM EndpointHit e " + + "WHERE e.timestamp BETWEEN :start AND :end " + + "AND (:uris IS NULL OR e.uri IN :uris) " + + "GROUP BY e.app, e.uri " + + "ORDER BY COUNT(DISTINCT e.ip) DESC") + List getUniqueStats( + @Param("start") LocalDateTime start, + @Param("end") LocalDateTime end, + @Param("uris") List uris); + + + + +} diff --git a/stats/stats-server/src/main/java/ewm/stat/service/EndpointHitService.java b/stats/stats-server/src/main/java/ewm/stat/service/EndpointHitService.java new file mode 100644 index 0000000..8ea6ec3 --- /dev/null +++ b/stats/stats-server/src/main/java/ewm/stat/service/EndpointHitService.java @@ -0,0 +1,14 @@ +package ewm.stat.service; + +import dto.CreateDto; +import dto.ViewStatsDto; + +import java.time.LocalDateTime; +import java.util.List; + +public interface EndpointHitService { + + void create(CreateDto createDto); + + List getStats(LocalDateTime start, LocalDateTime end, List uris, boolean unique); +} diff --git a/stats/stats-server/src/main/java/ewm/stat/service/EndpointHitServiceImpl.java b/stats/stats-server/src/main/java/ewm/stat/service/EndpointHitServiceImpl.java new file mode 100644 index 0000000..a159f04 --- /dev/null +++ b/stats/stats-server/src/main/java/ewm/stat/service/EndpointHitServiceImpl.java @@ -0,0 +1,38 @@ +package ewm.stat.service; + +import dto.CreateDto; +import dto.ViewStatsDto; +import ewm.stat.EndpointHit; +import ewm.stat.EndpointHitMapper; +import ewm.stat.EndpointHitRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; + +@Transactional +@Service +@RequiredArgsConstructor +public class EndpointHitServiceImpl implements EndpointHitService{ + private final EndpointHitRepository repository; + private final EndpointHitMapper mapper; + + @Override + public void create(CreateDto createDto) { + EndpointHit endpointHit = mapper.dtoToModel(createDto); + repository.save(endpointHit); + } + + @Override + public List getStats(LocalDateTime start, LocalDateTime end, List uris, boolean unique) { + if (unique) { + return repository.getUniqueStats(start, end, uris); + } else { + return repository.getStats(start, end, uris); + } + } + + +} diff --git a/stats/stats-server/src/main/resources/application.properties b/stats/stats-server/src/main/resources/application.properties new file mode 100644 index 0000000..2ea3019 --- /dev/null +++ b/stats/stats-server/src/main/resources/application.properties @@ -0,0 +1,21 @@ + +server.port=9090 +spring.output.ansi.enabled=ALWAYS +spring.jpa.hibernate.ddl-auto=none +spring.jpa.properties.hibernate.format_sql=true +spring.sql.init.mode=always + +spring.mvc.format.date-time=yyyy-MM-dd HH:mm:ss + +logging.level.org.zalando.logbook= TRACE + +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 + + +spring.datasource.driverClassName=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:6542/ewm-stats +spring.datasource.username=stat +spring.datasource.password=stat \ No newline at end of file diff --git a/stats/stats-server/src/main/resources/schema.sql b/stats/stats-server/src/main/resources/schema.sql new file mode 100644 index 0000000..cb63d1d --- /dev/null +++ b/stats/stats-server/src/main/resources/schema.sql @@ -0,0 +1,8 @@ + +CREATE TABLE IF NOT EXISTS endpoint_hits ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + app VARCHAR(200) NOT NULL, + uri VARCHAR(200) NOT NULL, + ip VARCHAR(200) NOT NULL, + timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL +); From 099aa0060c854eb0856e7a4626c04e3f2f22663e Mon Sep 17 00:00:00 2001 From: Just Roma Date: Fri, 18 Jul 2025 13:16:34 +0500 Subject: [PATCH 2/6] work --- docker-compose.yml | 2 +- stats/stats-client/pom.xml | 62 +++++++++++++++++ .../src/main/java/client/StatsClient.java | 67 +++++++++++++++++++ .../src/main/java/dto/CreateDto.java | 6 +- .../src/main/java/dto/ViewStatsDto.java | 3 +- .../java/ewm/stat/EndpointHitController.java | 5 +- .../java/ewm/stat/EndpointHitRepository.java | 2 - .../stat/service/EndpointHitServiceImpl.java | 2 +- 8 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 stats/stats-client/src/main/java/client/StatsClient.java diff --git a/docker-compose.yml b/docker-compose.yml index 883ab4e..1e26a3e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: '3.8' +version: '3.1' services: stats-server: diff --git a/stats/stats-client/pom.xml b/stats/stats-client/pom.xml index 05bd8e1..c65653f 100644 --- a/stats/stats-client/pom.xml +++ b/stats/stats-client/pom.xml @@ -12,6 +12,68 @@ stats-client + + + org.zalando + logbook-spring-boot-starter + 3.7.2 + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.hibernate.validator + hibernate-validator + + + + org.apache.httpcomponents.client5 + httpclient5 + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + ru.practicum + stats-dto + 0.0.1-SNAPSHOT + compile + + + ru.practicum + stats-server + 0.0.1-SNAPSHOT + compile + + + 22 22 diff --git a/stats/stats-client/src/main/java/client/StatsClient.java b/stats/stats-client/src/main/java/client/StatsClient.java new file mode 100644 index 0000000..79a3337 --- /dev/null +++ b/stats/stats-client/src/main/java/client/StatsClient.java @@ -0,0 +1,67 @@ +package client; + +import dto.CreateDto; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; + +import java.time.LocalDateTime; +import java.util.List; + + +@Service +public class StatsClient { + @Value("${client.url}") + private String serverUrl; + private final RestTemplate rest; + + public StatsClient() { + this.rest = new RestTemplate(); + HttpClient httpClient = HttpClientBuilder.create().build(); + HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); + rest.setRequestFactory(requestFactory); + } + + public ResponseEntity save(CreateDto createDto) { + ResponseEntity response; + try { + response = rest.postForEntity(serverUrl + "/createDto", createDto, Object.class); + } catch (HttpStatusCodeException e) { + return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsByteArray()); + } + ResponseEntity.BodyBuilder responseBuilder = ResponseEntity.status(response.getStatusCode()); + if (response.hasBody()) { + return responseBuilder.body(response.getBody()); + } + return responseBuilder.build(); + } + + public ResponseEntity getStats(LocalDateTime start, LocalDateTime end, List uris, Boolean unique) { + StringBuilder url = new StringBuilder(serverUrl + "/stats?"); + for (String uri : uris) { + url.append("&uris=").append(uri); + } + url.append("&unique=").append(unique); + url.append("&start=").append(start); + url.append("&end=").append(end); + + ResponseEntity response; + try { + response = rest.exchange(url.toString(), HttpMethod.GET, null, Object.class); + } catch (HttpStatusCodeException e) { + return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsByteArray()); + } + ResponseEntity.BodyBuilder responseBuilder = ResponseEntity.status(response.getStatusCode()); + if (response.hasBody()) { + return responseBuilder.body(response.getBody()); + } + return responseBuilder.build(); + } +} + diff --git a/stats/stats-dto/src/main/java/dto/CreateDto.java b/stats/stats-dto/src/main/java/dto/CreateDto.java index 22cbd3f..f108834 100644 --- a/stats/stats-dto/src/main/java/dto/CreateDto.java +++ b/stats/stats-dto/src/main/java/dto/CreateDto.java @@ -3,13 +3,11 @@ import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.FutureOrPresent; import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import lombok.*; import java.time.LocalDateTime; +@Builder @Setter @Getter @NoArgsConstructor diff --git a/stats/stats-dto/src/main/java/dto/ViewStatsDto.java b/stats/stats-dto/src/main/java/dto/ViewStatsDto.java index bdfd1ec..23044f8 100644 --- a/stats/stats-dto/src/main/java/dto/ViewStatsDto.java +++ b/stats/stats-dto/src/main/java/dto/ViewStatsDto.java @@ -1,6 +1,7 @@ package dto; -import lombok.*; +import lombok.Getter; +import lombok.Setter; @Getter diff --git a/stats/stats-server/src/main/java/ewm/stat/EndpointHitController.java b/stats/stats-server/src/main/java/ewm/stat/EndpointHitController.java index 86af090..c0d0752 100644 --- a/stats/stats-server/src/main/java/ewm/stat/EndpointHitController.java +++ b/stats/stats-server/src/main/java/ewm/stat/EndpointHitController.java @@ -3,8 +3,10 @@ import dto.CreateDto; import dto.ViewStatsDto; import ewm.stat.service.EndpointHitService; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; @@ -13,12 +15,13 @@ @RestController @RequiredArgsConstructor @RequestMapping +@Validated public class EndpointHitController { private final EndpointHitService service; @ResponseStatus(HttpStatus.CREATED) @PostMapping("/hit") - public void create(@RequestBody CreateDto createDto) { + public void create(@RequestBody @Valid CreateDto createDto) { service.create(createDto); } diff --git a/stats/stats-server/src/main/java/ewm/stat/EndpointHitRepository.java b/stats/stats-server/src/main/java/ewm/stat/EndpointHitRepository.java index 67ba146..5075d2b 100644 --- a/stats/stats-server/src/main/java/ewm/stat/EndpointHitRepository.java +++ b/stats/stats-server/src/main/java/ewm/stat/EndpointHitRepository.java @@ -33,6 +33,4 @@ List getUniqueStats( @Param("uris") List uris); - - } diff --git a/stats/stats-server/src/main/java/ewm/stat/service/EndpointHitServiceImpl.java b/stats/stats-server/src/main/java/ewm/stat/service/EndpointHitServiceImpl.java index a159f04..5059a7f 100644 --- a/stats/stats-server/src/main/java/ewm/stat/service/EndpointHitServiceImpl.java +++ b/stats/stats-server/src/main/java/ewm/stat/service/EndpointHitServiceImpl.java @@ -15,7 +15,7 @@ @Transactional @Service @RequiredArgsConstructor -public class EndpointHitServiceImpl implements EndpointHitService{ +public class EndpointHitServiceImpl implements EndpointHitService { private final EndpointHitRepository repository; private final EndpointHitMapper mapper; From d01caac4306f8d8c444ff868935a18328f92b945 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Fri, 18 Jul 2025 13:43:08 +0500 Subject: [PATCH 3/6] fix --- .../src/main/resources/application.properties | 1 + .../src/main/resources/application-test.properties | 10 ++++++++++ .../src/main/resources/application.properties | 3 ++- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 stats/stats-client/src/main/resources/application.properties create mode 100644 stats/stats-server/src/main/resources/application-test.properties diff --git a/stats/stats-client/src/main/resources/application.properties b/stats/stats-client/src/main/resources/application.properties new file mode 100644 index 0000000..e8eb8a9 --- /dev/null +++ b/stats/stats-client/src/main/resources/application.properties @@ -0,0 +1 @@ +client.url=http://localhost:9090 \ No newline at end of file diff --git a/stats/stats-server/src/main/resources/application-test.properties b/stats/stats-server/src/main/resources/application-test.properties new file mode 100644 index 0000000..b649eba --- /dev/null +++ b/stats/stats-server/src/main/resources/application-test.properties @@ -0,0 +1,10 @@ +spring.output.ansi.enabled=ALWAYS + +spring.jpa.defer-datasource-initialization=true + +spring.config.activate.on-profile=test +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.url=jdbc:h2:mem:stats +spring.datasource.username=stats +spring.datasource.password=stats + diff --git a/stats/stats-server/src/main/resources/application.properties b/stats/stats-server/src/main/resources/application.properties index 2ea3019..0cec1dd 100644 --- a/stats/stats-server/src/main/resources/application.properties +++ b/stats/stats-server/src/main/resources/application.properties @@ -18,4 +18,5 @@ logging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUG spring.datasource.driverClassName=org.postgresql.Driver spring.datasource.url=jdbc:postgresql://localhost:6542/ewm-stats spring.datasource.username=stat -spring.datasource.password=stat \ No newline at end of file +spring.datasource.password=stat + From 0ac30f4b2b817ef6591f0e4b7290f29866b03f54 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Fri, 18 Jul 2025 14:12:14 +0500 Subject: [PATCH 4/6] fix 2 --- stats/stats-dto/src/main/java/dto/CreateDto.java | 3 ++- stats/stats-server/src/main/resources/application.properties | 2 +- .../resources/application.properties} | 0 3 files changed, 3 insertions(+), 2 deletions(-) rename stats/stats-server/src/{main/resources/application-test.properties => test/resources/application.properties} (100%) diff --git a/stats/stats-dto/src/main/java/dto/CreateDto.java b/stats/stats-dto/src/main/java/dto/CreateDto.java index f108834..66b023e 100644 --- a/stats/stats-dto/src/main/java/dto/CreateDto.java +++ b/stats/stats-dto/src/main/java/dto/CreateDto.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.FutureOrPresent; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Past; import lombok.*; import java.time.LocalDateTime; @@ -23,7 +24,7 @@ public class CreateDto { private String ip; @NotNull - @FutureOrPresent + @Past @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime timestamp; diff --git a/stats/stats-server/src/main/resources/application.properties b/stats/stats-server/src/main/resources/application.properties index 0cec1dd..a46de82 100644 --- a/stats/stats-server/src/main/resources/application.properties +++ b/stats/stats-server/src/main/resources/application.properties @@ -19,4 +19,4 @@ spring.datasource.driverClassName=org.postgresql.Driver spring.datasource.url=jdbc:postgresql://localhost:6542/ewm-stats spring.datasource.username=stat spring.datasource.password=stat - +spring.jpa.properties.hibernate.default_schema=public diff --git a/stats/stats-server/src/main/resources/application-test.properties b/stats/stats-server/src/test/resources/application.properties similarity index 100% rename from stats/stats-server/src/main/resources/application-test.properties rename to stats/stats-server/src/test/resources/application.properties From 8605ae2a25aeb912bd0afd2bdf3863b423c9d58d Mon Sep 17 00:00:00 2001 From: Just Roma Date: Fri, 18 Jul 2025 14:13:30 +0500 Subject: [PATCH 5/6] fix 3 --- stats/stats-dto/src/main/java/dto/CreateDto.java | 1 - 1 file changed, 1 deletion(-) diff --git a/stats/stats-dto/src/main/java/dto/CreateDto.java b/stats/stats-dto/src/main/java/dto/CreateDto.java index 66b023e..5d2d0e5 100644 --- a/stats/stats-dto/src/main/java/dto/CreateDto.java +++ b/stats/stats-dto/src/main/java/dto/CreateDto.java @@ -1,7 +1,6 @@ package dto; import com.fasterxml.jackson.annotation.JsonFormat; -import jakarta.validation.constraints.FutureOrPresent; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Past; import lombok.*; From a7020b8fd358e7325cfed9b1552e3a9c5b4181c9 Mon Sep 17 00:00:00 2001 From: Just Roma Date: Fri, 18 Jul 2025 21:47:25 +0500 Subject: [PATCH 6/6] fix 4 --- pom.xml | 3 --- stats/pom.xml | 10 ++++++++++ stats/stats-dto/pom.xml | 14 -------------- stats/stats-dto/src/main/java/dto/CreateDto.java | 2 +- .../src/main/java/ewm/stat/EndpointHit.java | 2 +- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/pom.xml b/pom.xml index 0e74b80..6a4fa1e 100644 --- a/pom.xml +++ b/pom.xml @@ -14,9 +14,6 @@ main-service stats - stats/stats-client - stats/stats-dto - stats/stats-server ru.practicum diff --git a/stats/pom.xml b/stats/pom.xml index 78a227e..7785b9b 100644 --- a/stats/pom.xml +++ b/stats/pom.xml @@ -10,7 +10,17 @@ + Explore With Me Stats + stats + 0.0.1-SNAPSHOT + pom + + + stats-client + stats-dto + stats-server + 21 diff --git a/stats/stats-dto/pom.xml b/stats/stats-dto/pom.xml index 57a04c2..26d9ae0 100644 --- a/stats/stats-dto/pom.xml +++ b/stats/stats-dto/pom.xml @@ -24,10 +24,6 @@ logbook-spring-boot-starter 3.7.2 - - org.springframework.boot - spring-boot-starter-web - org.springframework.boot @@ -39,16 +35,6 @@ spring-boot-starter-actuator - - org.hibernate.validator - hibernate-validator - - - - org.apache.httpcomponents.client5 - httpclient5 - - org.springframework.boot spring-boot-configuration-processor diff --git a/stats/stats-dto/src/main/java/dto/CreateDto.java b/stats/stats-dto/src/main/java/dto/CreateDto.java index 5d2d0e5..e2f6159 100644 --- a/stats/stats-dto/src/main/java/dto/CreateDto.java +++ b/stats/stats-dto/src/main/java/dto/CreateDto.java @@ -25,6 +25,6 @@ public class CreateDto { @NotNull @Past @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - LocalDateTime timestamp; + private LocalDateTime timestamp; } diff --git a/stats/stats-server/src/main/java/ewm/stat/EndpointHit.java b/stats/stats-server/src/main/java/ewm/stat/EndpointHit.java index 6ba22d7..d273330 100644 --- a/stats/stats-server/src/main/java/ewm/stat/EndpointHit.java +++ b/stats/stats-server/src/main/java/ewm/stat/EndpointHit.java @@ -29,6 +29,6 @@ public class EndpointHit { @Column(nullable = false) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - LocalDateTime timestamp; + private LocalDateTime timestamp; }