From e142f4c99110cd9d5c4943a5a84e192e306c5c60 Mon Sep 17 00:00:00 2001 From: IgorPushka Date: Wed, 27 Dec 2023 14:36:05 +0300 Subject: [PATCH] 1 iteration --- docker-compose.yml | 28 ++++-- event-service/DockerFile | 3 + event-service/pom.xml | 44 +++++++++ .../java/ru/practicum/EventServiceApp.java | 11 +++ .../src/main/resources/application.properties | 26 ++++++ pom.xml | 92 ++++++++++++++++++- statistics-service/dto-service/pom.xml | 40 ++++++++ .../java/ru/practicum/dto/InputEventDto.java | 22 +++++ .../java/ru/practicum/dto/OutputStatsDto.java | 18 ++++ .../exception/EntityNotFoundException.java | 9 ++ .../exception/EntityValidationException.java | 9 ++ .../ru/practicum/exception/ErrorHandler.java | 37 ++++++++ .../exception/model/ErrorResponse.java | 10 ++ statistics-service/http-client/pom.xml | 30 ++++++ .../java/ru/practicum/client/BaseClient.java | 73 +++++++++++++++ .../ru/practicum/client/StatisticsClient.java | 42 +++++++++ statistics-service/pom.xml | 25 +++++ .../statistics-server/Dockerfile | 3 + statistics-service/statistics-server/pom.xml | 44 +++++++++ .../ru/practicum/StatisticsController.java | 40 ++++++++ .../ru/practicum/StatisticsServerApp.java | 11 +++ .../main/java/ru/practicum/model/Stats.java | 33 +++++++ .../java/ru/practicum/model/StatsMapper.java | 11 +++ .../repository/StatisticsRepository.java | 29 ++++++ .../practicum/service/StatisticsService.java | 13 +++ .../service/StatisticsServiceImpl.java | 35 +++++++ .../src/main/resources/application.properties | 26 ++++++ .../src/main/resources/schema.sql | 7 ++ 28 files changed, 761 insertions(+), 10 deletions(-) create mode 100644 event-service/DockerFile create mode 100644 event-service/pom.xml create mode 100644 event-service/src/main/java/ru/practicum/EventServiceApp.java create mode 100644 event-service/src/main/resources/application.properties create mode 100644 statistics-service/dto-service/pom.xml create mode 100644 statistics-service/dto-service/src/main/java/ru/practicum/dto/InputEventDto.java create mode 100644 statistics-service/dto-service/src/main/java/ru/practicum/dto/OutputStatsDto.java create mode 100644 statistics-service/dto-service/src/main/java/ru/practicum/exception/EntityNotFoundException.java create mode 100644 statistics-service/dto-service/src/main/java/ru/practicum/exception/EntityValidationException.java create mode 100644 statistics-service/dto-service/src/main/java/ru/practicum/exception/ErrorHandler.java create mode 100644 statistics-service/dto-service/src/main/java/ru/practicum/exception/model/ErrorResponse.java create mode 100644 statistics-service/http-client/pom.xml create mode 100644 statistics-service/http-client/src/main/java/ru/practicum/client/BaseClient.java create mode 100644 statistics-service/http-client/src/main/java/ru/practicum/client/StatisticsClient.java create mode 100644 statistics-service/pom.xml create mode 100644 statistics-service/statistics-server/Dockerfile create mode 100644 statistics-service/statistics-server/pom.xml create mode 100644 statistics-service/statistics-server/src/main/java/ru/practicum/StatisticsController.java create mode 100644 statistics-service/statistics-server/src/main/java/ru/practicum/StatisticsServerApp.java create mode 100644 statistics-service/statistics-server/src/main/java/ru/practicum/model/Stats.java create mode 100644 statistics-service/statistics-server/src/main/java/ru/practicum/model/StatsMapper.java create mode 100644 statistics-service/statistics-server/src/main/java/ru/practicum/repository/StatisticsRepository.java create mode 100644 statistics-service/statistics-server/src/main/java/ru/practicum/service/StatisticsService.java create mode 100644 statistics-service/statistics-server/src/main/java/ru/practicum/service/StatisticsServiceImpl.java create mode 100644 statistics-service/statistics-server/src/main/resources/application.properties create mode 100644 statistics-service/statistics-server/src/main/resources/schema.sql diff --git a/docker-compose.yml b/docker-compose.yml index b387e1a6..bb8201aa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,15 +1,25 @@ version: '3.1' services: - stats-server: - ports: - - "9090:9090" - stats-db: + statistics-db: image: postgres:14-alpine - - ewm-service: + container_name: statistics_postgres_container ports: - - "8080:8080" + - "6541:5432" + environment: + - POSTGRES_DB=statistics-db + - POSTGRES_USER=iamstatsroot + - POSTGRES_PASSWORD=iamstatsroot - ewm-db: - image: postgres:14-alpine + statistics-server: + build: statistics-service/statistics-server + image: statistics_server_image + container_name: statistics_server_container + ports: + - "9090:9090" + depends_on: + - statistics-db + environment: + - SPRING_DATASOURCE_URL=jdbc:postgresql://statistics-db:5432/statistics-db + - SPRING_DATASOURCE_USERNAME=iamstatsroot + - SPRING_DATASOURCE_PASSWORD=iamstatsroot diff --git a/event-service/DockerFile b/event-service/DockerFile new file mode 100644 index 00000000..ae6fb44c --- /dev/null +++ b/event-service/DockerFile @@ -0,0 +1,3 @@ +FROM amazoncorretto:11-alpine-jdk +COPY target/*.jar event-service.jar +ENTRYPOINT ["java","-jar","/event-service.jar"] \ No newline at end of file diff --git a/event-service/pom.xml b/event-service/pom.xml new file mode 100644 index 00000000..6d3e9f85 --- /dev/null +++ b/event-service/pom.xml @@ -0,0 +1,44 @@ + + + + explore-with-me + ru.practicum + 0.0.1-SNAPSHOT + + 4.0.0 + + event-service + + + 11 + 11 + + + + + ru.practicum + http-client + 0.0.1-SNAPSHOT + compile + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + \ No newline at end of file diff --git a/event-service/src/main/java/ru/practicum/EventServiceApp.java b/event-service/src/main/java/ru/practicum/EventServiceApp.java new file mode 100644 index 00000000..053837e6 --- /dev/null +++ b/event-service/src/main/java/ru/practicum/EventServiceApp.java @@ -0,0 +1,11 @@ +package ru.practicum; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class EventServiceApp { + public static void main(String[] args) { + SpringApplication.run(EventServiceApp.class, args); + } +} diff --git a/event-service/src/main/resources/application.properties b/event-service/src/main/resources/application.properties new file mode 100644 index 00000000..28b3b596 --- /dev/null +++ b/event-service/src/main/resources/application.properties @@ -0,0 +1,26 @@ +server.port=8080 +statistics-server.url=http://localhost:9090 + +spring.jpa.hibernate.ddl-auto=none +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialect +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.properties.hibernate.show_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 + +#--- +spring.config.activate.on-profile=dev +spring.datasource.driverClassName=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/event-db +spring.datasource.username=iameventroot +spring.datasource.password=iameventroot +#--- +spring.config.activate.on-profile=ci,test +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.url=jdbc:h2:mem:event-db +spring.datasource.username=test +spring.datasource.password=test \ No newline at end of file diff --git a/pom.xml b/pom.xml index ad386209..796cf67e 100644 --- a/pom.xml +++ b/pom.xml @@ -2,8 +2,12 @@ 4.0.0 + + event-service + statistics-service + - + org.springframework.boot spring-boot-starter-parent 2.7.5 @@ -17,6 +21,64 @@ 0.0.1-SNAPSHOT pom + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-web + + + + org.postgresql + postgresql + runtime + + + + com.h2database + h2 + runtime + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.projectlombok + lombok + true + + + + org.mapstruct + mapstruct + 1.5.5.Final + + + + org.hamcrest + hamcrest-all + 1.3 + + + 11 UTF-8 @@ -34,6 +96,34 @@ + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 11 + 11 + + + org.mapstruct + mapstruct-processor + 1.5.5.Final + + + org.projectlombok + lombok + 1.18.20 + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + + + + + org.apache.maven.plugins maven-checkstyle-plugin diff --git a/statistics-service/dto-service/pom.xml b/statistics-service/dto-service/pom.xml new file mode 100644 index 00000000..21a72c8a --- /dev/null +++ b/statistics-service/dto-service/pom.xml @@ -0,0 +1,40 @@ + + + + statistics-service + ru.practicum + 0.0.1-SNAPSHOT + + 4.0.0 + + dto-service + jar + + + 11 + 11 + UTF-8 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + + \ No newline at end of file diff --git a/statistics-service/dto-service/src/main/java/ru/practicum/dto/InputEventDto.java b/statistics-service/dto-service/src/main/java/ru/practicum/dto/InputEventDto.java new file mode 100644 index 00000000..5b54ba36 --- /dev/null +++ b/statistics-service/dto-service/src/main/java/ru/practicum/dto/InputEventDto.java @@ -0,0 +1,22 @@ +package ru.practicum.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Builder +public class InputEventDto { + private long id; + private String app; + private String uri; + private String ip; + private LocalDateTime requestDate; +} diff --git a/statistics-service/dto-service/src/main/java/ru/practicum/dto/OutputStatsDto.java b/statistics-service/dto-service/src/main/java/ru/practicum/dto/OutputStatsDto.java new file mode 100644 index 00000000..dfeebf76 --- /dev/null +++ b/statistics-service/dto-service/src/main/java/ru/practicum/dto/OutputStatsDto.java @@ -0,0 +1,18 @@ +package ru.practicum.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +public class OutputStatsDto { + private String app; + private String uri; + private long hits; +} diff --git a/statistics-service/dto-service/src/main/java/ru/practicum/exception/EntityNotFoundException.java b/statistics-service/dto-service/src/main/java/ru/practicum/exception/EntityNotFoundException.java new file mode 100644 index 00000000..309bc4d1 --- /dev/null +++ b/statistics-service/dto-service/src/main/java/ru/practicum/exception/EntityNotFoundException.java @@ -0,0 +1,9 @@ +package ru.practicum.exception; + +public class EntityNotFoundException extends RuntimeException { + + public EntityNotFoundException(String message) { + super(message); + } + +} diff --git a/statistics-service/dto-service/src/main/java/ru/practicum/exception/EntityValidationException.java b/statistics-service/dto-service/src/main/java/ru/practicum/exception/EntityValidationException.java new file mode 100644 index 00000000..02be4770 --- /dev/null +++ b/statistics-service/dto-service/src/main/java/ru/practicum/exception/EntityValidationException.java @@ -0,0 +1,9 @@ +package ru.practicum.exception; + +public class EntityValidationException extends RuntimeException { + + public EntityValidationException(String message) { + super(message); + } + +} diff --git a/statistics-service/dto-service/src/main/java/ru/practicum/exception/ErrorHandler.java b/statistics-service/dto-service/src/main/java/ru/practicum/exception/ErrorHandler.java new file mode 100644 index 00000000..d457a9f8 --- /dev/null +++ b/statistics-service/dto-service/src/main/java/ru/practicum/exception/ErrorHandler.java @@ -0,0 +1,37 @@ +package ru.practicum.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; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; +import ru.practicum.exception.model.ErrorResponse; + +@RestControllerAdvice +public class ErrorHandler extends ResponseEntityExceptionHandler { + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ErrorResponse handleEntityInvalidException(final EntityValidationException e) { + return new ErrorResponse( + e.getMessage() + ); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.NOT_FOUND) + public ErrorResponse handleEntityNotFoundException(final EntityNotFoundException e) { + return new ErrorResponse( + e.getMessage() + ); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ErrorResponse handleUnexpectedException(final Throwable e) { + return new ErrorResponse( + "Произошла непредвиденная ошибка." + ); + } +} + diff --git a/statistics-service/dto-service/src/main/java/ru/practicum/exception/model/ErrorResponse.java b/statistics-service/dto-service/src/main/java/ru/practicum/exception/model/ErrorResponse.java new file mode 100644 index 00000000..da1a3ae7 --- /dev/null +++ b/statistics-service/dto-service/src/main/java/ru/practicum/exception/model/ErrorResponse.java @@ -0,0 +1,10 @@ +package ru.practicum.exception.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class ErrorResponse { + private final String error; +} diff --git a/statistics-service/http-client/pom.xml b/statistics-service/http-client/pom.xml new file mode 100644 index 00000000..2d200ff5 --- /dev/null +++ b/statistics-service/http-client/pom.xml @@ -0,0 +1,30 @@ + + + + statistics-service + ru.practicum + 0.0.1-SNAPSHOT + + 4.0.0 + + http-client + jar + + + 11 + 11 + UTF-8 + + + + + ru.practicum + dto-service + 0.0.1-SNAPSHOT + compile + + + + \ No newline at end of file diff --git a/statistics-service/http-client/src/main/java/ru/practicum/client/BaseClient.java b/statistics-service/http-client/src/main/java/ru/practicum/client/BaseClient.java new file mode 100644 index 00000000..92651ece --- /dev/null +++ b/statistics-service/http-client/src/main/java/ru/practicum/client/BaseClient.java @@ -0,0 +1,73 @@ +package ru.practicum.client; + +import java.util.List; +import java.util.Map; + +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.lang.Nullable; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; + +public class BaseClient { + protected final RestTemplate rest; + + public BaseClient(RestTemplate rest) { + this.rest = rest; + } + + protected ResponseEntity post(String path, T body) { + return post(path, null, body); + } + + protected ResponseEntity post(String path, @Nullable Map parameters, T body) { + return makeAndSendRequest(HttpMethod.POST, path, parameters, body); + } + + protected ResponseEntity get(String path, @Nullable Map parameters) { + return makeAndSendRequest(HttpMethod.GET, path, parameters, null); + } + + private ResponseEntity makeAndSendRequest( + HttpMethod method, String path, @Nullable Map parameters, @Nullable T body) { + + HttpEntity requestEntity = new HttpEntity<>(body, defaultHeaders()); + + ResponseEntity response; + + try { + if (parameters != null) { + response = rest.exchange(path, method, requestEntity, Object.class, parameters); + } else { + response = rest.exchange(path, method, requestEntity, Object.class); + } + } catch (HttpStatusCodeException e) { + return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsByteArray()); + } + return prepareGatewayResponse(response); + } + + private HttpHeaders defaultHeaders() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(List.of(MediaType.APPLICATION_JSON)); + return headers; + } + + private static ResponseEntity prepareGatewayResponse(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(); + } +} diff --git a/statistics-service/http-client/src/main/java/ru/practicum/client/StatisticsClient.java b/statistics-service/http-client/src/main/java/ru/practicum/client/StatisticsClient.java new file mode 100644 index 00000000..2474b90e --- /dev/null +++ b/statistics-service/http-client/src/main/java/ru/practicum/client/StatisticsClient.java @@ -0,0 +1,42 @@ +package ru.practicum.client; + +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 ru.practicum.dto.InputEventDto; + +import java.util.List; +import java.util.Map; + +@Service +public class StatisticsClient extends BaseClient { + + @Autowired + public StatisticsClient(@Value("${stats-service.url}") String serverUrl, RestTemplateBuilder builder) { + super( + builder + .uriTemplateHandler(new DefaultUriBuilderFactory(serverUrl)) + .requestFactory(HttpComponentsClientHttpRequestFactory::new) + .build() + ); + } + + public ResponseEntity save(InputEventDto dto) { + return post("/hit", dto); + } + + public ResponseEntity getStats(String start, String end, List uris, Boolean unique) { + Map parameters = Map.of( + "start", start, + "end", end, + "uris", uris, + "unique", unique + ); + return get("/stats?start={start}&end={end}&uris={uris}&unique={unique}", parameters); + } + +} diff --git a/statistics-service/pom.xml b/statistics-service/pom.xml new file mode 100644 index 00000000..f8432c37 --- /dev/null +++ b/statistics-service/pom.xml @@ -0,0 +1,25 @@ + + + + explore-with-me + ru.practicum + 0.0.1-SNAPSHOT + + 4.0.0 + + statistics-service + pom + + dto-service + http-client + statistics-server + + + + 11 + 11 + + + \ No newline at end of file diff --git a/statistics-service/statistics-server/Dockerfile b/statistics-service/statistics-server/Dockerfile new file mode 100644 index 00000000..d1ea39f4 --- /dev/null +++ b/statistics-service/statistics-server/Dockerfile @@ -0,0 +1,3 @@ +FROM amazoncorretto:11-alpine-jdk +COPY target/*.jar statistics-server.jar +ENTRYPOINT ["java","-jar","statistics-server.jar"] \ No newline at end of file diff --git a/statistics-service/statistics-server/pom.xml b/statistics-service/statistics-server/pom.xml new file mode 100644 index 00000000..57db8e4e --- /dev/null +++ b/statistics-service/statistics-server/pom.xml @@ -0,0 +1,44 @@ + + + + statistics-service + ru.practicum + 0.0.1-SNAPSHOT + + 4.0.0 + + statistics-server + + + 11 + 11 + + + + ru.practicum + dto-service + 0.0.1-SNAPSHOT + compile + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + \ No newline at end of file diff --git a/statistics-service/statistics-server/src/main/java/ru/practicum/StatisticsController.java b/statistics-service/statistics-server/src/main/java/ru/practicum/StatisticsController.java new file mode 100644 index 00000000..00bc0cee --- /dev/null +++ b/statistics-service/statistics-server/src/main/java/ru/practicum/StatisticsController.java @@ -0,0 +1,40 @@ +package ru.practicum; + +import lombok.RequiredArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import ru.practicum.dto.InputEventDto; +import ru.practicum.dto.OutputStatsDto; +import ru.practicum.exception.EntityValidationException; +import ru.practicum.service.StatisticsService; + +import java.time.LocalDateTime; +import java.util.List; + +@RestController +@RequiredArgsConstructor +public class StatisticsController { + + private final StatisticsService service; + + @PostMapping("/hit") + public InputEventDto saveEventStats(@RequestBody InputEventDto dto) { + return service.saveEventStats(dto); + } + + @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) { + if (start.equals(end) || start.isAfter(end)) { + throw new EntityValidationException("Некорректные начало и конец!"); + } + return service.getStats(start, end, uris, unique); + } +} diff --git a/statistics-service/statistics-server/src/main/java/ru/practicum/StatisticsServerApp.java b/statistics-service/statistics-server/src/main/java/ru/practicum/StatisticsServerApp.java new file mode 100644 index 00000000..112dcdfd --- /dev/null +++ b/statistics-service/statistics-server/src/main/java/ru/practicum/StatisticsServerApp.java @@ -0,0 +1,11 @@ +package ru.practicum; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class StatisticsServerApp { + public static void main(String[] args) { + SpringApplication.run(StatisticsServerApp.class, args); + } +} diff --git a/statistics-service/statistics-server/src/main/java/ru/practicum/model/Stats.java b/statistics-service/statistics-server/src/main/java/ru/practicum/model/Stats.java new file mode 100644 index 00000000..a63358f5 --- /dev/null +++ b/statistics-service/statistics-server/src/main/java/ru/practicum/model/Stats.java @@ -0,0 +1,33 @@ +package ru.practicum.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.time.LocalDateTime; + +@Entity +@Table(name = "statistics") +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Getter +@Setter +public class Stats { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + private String app; + private String uri; + private String ip; + @Column(name = "request_date") + private LocalDateTime requestDate; +} diff --git a/statistics-service/statistics-server/src/main/java/ru/practicum/model/StatsMapper.java b/statistics-service/statistics-server/src/main/java/ru/practicum/model/StatsMapper.java new file mode 100644 index 00000000..f73ca042 --- /dev/null +++ b/statistics-service/statistics-server/src/main/java/ru/practicum/model/StatsMapper.java @@ -0,0 +1,11 @@ +package ru.practicum.model; + +import org.mapstruct.Mapper; +import ru.practicum.dto.InputEventDto; + +@Mapper(componentModel = "spring") +public interface StatsMapper { + Stats mapInputEventDtoToStats(InputEventDto dto); + + InputEventDto mapStatsToInputEventDto(Stats stats); +} diff --git a/statistics-service/statistics-server/src/main/java/ru/practicum/repository/StatisticsRepository.java b/statistics-service/statistics-server/src/main/java/ru/practicum/repository/StatisticsRepository.java new file mode 100644 index 00000000..409ea9d5 --- /dev/null +++ b/statistics-service/statistics-server/src/main/java/ru/practicum/repository/StatisticsRepository.java @@ -0,0 +1,29 @@ +package ru.practicum.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import ru.practicum.dto.OutputStatsDto; +import ru.practicum.model.Stats; + +import java.time.LocalDateTime; +import java.util.List; + +@Repository +public interface StatisticsRepository extends JpaRepository { + @Query(" SELECT new ru.practicum.dto.OutputStatsDto(s.app, s.uri, COUNT(DISTINCT s.ip)) " + + "FROM Stats s " + + "WHERE s.requestDate BETWEEN ?1 AND ?2 " + + "AND (s.uri IN (?3) OR (?3) is NULL) " + + "GROUP BY s.app, s.uri " + + "ORDER BY COUNT(DISTINCT s.ip) DESC ") + List findUniqueStats(LocalDateTime start, LocalDateTime end, List uris); + + @Query(" SELECT new ru.practicum.dto.OutputStatsDto(s.app, s.uri, COUNT(s.ip)) " + + "FROM Stats s " + + "WHERE s.requestDate BETWEEN ?1 AND ?2 " + + "AND (s.uri IN (?3) OR (?3) is NULL) " + + "GROUP BY s.app, s.uri " + + "ORDER BY COUNT(s.ip) DESC ") + List findStats(LocalDateTime start, LocalDateTime end, List uris); +} diff --git a/statistics-service/statistics-server/src/main/java/ru/practicum/service/StatisticsService.java b/statistics-service/statistics-server/src/main/java/ru/practicum/service/StatisticsService.java new file mode 100644 index 00000000..bced3331 --- /dev/null +++ b/statistics-service/statistics-server/src/main/java/ru/practicum/service/StatisticsService.java @@ -0,0 +1,13 @@ +package ru.practicum.service; + +import ru.practicum.dto.InputEventDto; +import ru.practicum.dto.OutputStatsDto; + +import java.time.LocalDateTime; +import java.util.List; + +public interface StatisticsService { + InputEventDto saveEventStats(InputEventDto dto); + + List getStats(LocalDateTime start, LocalDateTime end, List uris, boolean unique); +} diff --git a/statistics-service/statistics-server/src/main/java/ru/practicum/service/StatisticsServiceImpl.java b/statistics-service/statistics-server/src/main/java/ru/practicum/service/StatisticsServiceImpl.java new file mode 100644 index 00000000..cb56279d --- /dev/null +++ b/statistics-service/statistics-server/src/main/java/ru/practicum/service/StatisticsServiceImpl.java @@ -0,0 +1,35 @@ +package ru.practicum.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.practicum.dto.InputEventDto; +import ru.practicum.dto.OutputStatsDto; +import ru.practicum.model.Stats; +import ru.practicum.model.StatsMapper; +import ru.practicum.repository.StatisticsRepository; + +import java.time.LocalDateTime; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class StatisticsServiceImpl implements StatisticsService { + + private final StatisticsRepository repository; + private final StatsMapper mapper; + + @Override + public InputEventDto saveEventStats(InputEventDto dto) { + Stats stats = mapper.mapInputEventDtoToStats(dto); + stats.setRequestDate(LocalDateTime.now()); + return mapper.mapStatsToInputEventDto(repository.saveAndFlush(stats)); + } + + public List getStats(LocalDateTime start, LocalDateTime end, List uris, boolean unique) { + if (unique) { + return repository.findUniqueStats(start, end, uris); + } else { + return repository.findStats(start, end, uris); + } + } +} diff --git a/statistics-service/statistics-server/src/main/resources/application.properties b/statistics-service/statistics-server/src/main/resources/application.properties new file mode 100644 index 00000000..c90c0b03 --- /dev/null +++ b/statistics-service/statistics-server/src/main/resources/application.properties @@ -0,0 +1,26 @@ +server.port=9090 + +spring.jpa.hibernate.ddl-auto=none +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialect +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.properties.hibernate.show_sql=true +spring.jpa.show-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 + +#--- +spring.config.activate.on-profile=dev +spring.datasource.driverClassName=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/statistics-db +spring.datasource.username=iamstatsroot +spring.datasource.password=iamstatsroot +#--- +spring.config.activate.on-profile=ci,test +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.url=jdbc:h2:mem:statistics-db +spring.datasource.username=test +spring.datasource.password=test \ No newline at end of file diff --git a/statistics-service/statistics-server/src/main/resources/schema.sql b/statistics-service/statistics-server/src/main/resources/schema.sql new file mode 100644 index 00000000..98059721 --- /dev/null +++ b/statistics-service/statistics-server/src/main/resources/schema.sql @@ -0,0 +1,7 @@ +create table if not exists statistics ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + app varchar, + uri varchar, + ip varchar, + request_date timestamp WITHOUT TIME ZONE +); \ No newline at end of file