From da5d1a22a00ea5cda600819d6454a1ec120f9f57 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 00:39:20 +0500 Subject: [PATCH 001/118] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B2=D0=B0=D1=8F=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D1=8B=D1=82=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Docker.java | 21 + pom.xml | 21 + .../ErrorHandler.java | 5 +- .../practicum/filmorate/model/Buffer.java | 41 ++ .../practicum/filmorate/model/Film.java | 43 +- .../filmorate/model/FilmRequest.java | 35 ++ .../filmorate/model/FriendRequest.java | 15 + .../practicum/filmorate/model/Genre.java | 13 + .../filmorate/model/GenreConstant.java | 13 + .../yandex/practicum/filmorate/model/Mpa.java | 13 + .../filmorate/model/MpaConstant.java | 13 + .../practicum/filmorate/model/User.java | 34 +- .../filmorate/storage/film/FilmDbStorage.java | 161 ++++++++ .../storage/film/InMemoryFilmStorage.java | 266 ++++++------- .../storage/user/InMemoryUserStorage.java | 366 +++++++++--------- .../filmorate/storage/user/UserDbStorage.java | 213 ++++++++++ src/main/resources/application.properties | 7 +- src/main/resources/data.sql | 15 + src/main/resources/schema.sql | 58 +++ src/main/resources/schema.sql.bak | 51 +++ .../filmorate/FilmControllerTest.java | 126 ------ .../filmorate/FilmoRateApplicationTests.java | 54 +++ .../filmorate/InMemoryUserStorageTest.java | 95 ----- .../filmorate/UserControllerTest.java | 100 ----- .../filmorate/UserDbStorageTest.java | 113 ++++++ 25 files changed, 1216 insertions(+), 676 deletions(-) create mode 100644 Docker.java rename src/main/java/ru/yandex/practicum/filmorate/{exception => controller}/ErrorHandler.java (88%) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/Buffer.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/FilmRequest.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/FriendRequest.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/Genre.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/GenreConstant.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/MpaConstant.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java create mode 100644 src/main/resources/data.sql create mode 100644 src/main/resources/schema.sql create mode 100644 src/main/resources/schema.sql.bak delete mode 100644 src/test/java/ru/yandex/practicum/filmorate/FilmControllerTest.java create mode 100644 src/test/java/ru/yandex/practicum/filmorate/FilmoRateApplicationTests.java delete mode 100644 src/test/java/ru/yandex/practicum/filmorate/InMemoryUserStorageTest.java delete mode 100644 src/test/java/ru/yandex/practicum/filmorate/UserControllerTest.java create mode 100644 src/test/java/ru/yandex/practicum/filmorate/UserDbStorageTest.java diff --git a/Docker.java b/Docker.java new file mode 100644 index 0000000..7875079 --- /dev/null +++ b/Docker.java @@ -0,0 +1,21 @@ +# первый (вспомогательный) этап с именем builder +FROM amazoncorretto:22-alpine as builder +# устанавливаем application в качестве рабочей директории +WORKDIR application +# копируем артефакт в папку application в контейнере +COPY target/*.jar app.jar +# используем специальный режим запуска Spring Boot приложения, +# который активирует распаковку итогового jar-файла на составляющие +RUN java -Djarmode=layertools -jar app.jar extract + +# заключительный этап, создающий финальный образ +FROM amazoncorretto:22-alpine +# поочерёдно копируем необходимые для приложения файлы, +# которые были распакованы из артефакта на предыдущем этапе; +# при этом каждая инструкция COPY создаёт новый слой +COPY --from=builder /application/dependencies/ ./ +COPY --from=builder /application/spring-boot-loader/ ./ +COPY --from=builder /application/snapshot-dependencies/ ./ +COPY --from=builder /application/application ./ +# в качестве команды указываем запуск специального загрузчика +ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"] \ No newline at end of file diff --git a/pom.xml b/pom.xml index a973f82..b68f756 100644 --- a/pom.xml +++ b/pom.xml @@ -61,6 +61,27 @@ 4.0.0 test + + + + com.h2database + h2 + runtime + + + + + org.springframework.boot + spring-boot-starter-jdbc + + + + + org.springframework.boot + spring-boot-starter-test + test + + diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java similarity index 88% rename from src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java rename to src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java index e03903a..65e9aa5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java @@ -1,4 +1,4 @@ -package ru.yandex.practicum.filmorate.exception; +package ru.yandex.practicum.filmorate.controller; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -6,6 +6,9 @@ import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; +import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.exception.ValidationException; import java.util.Map; diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Buffer.java b/src/main/java/ru/yandex/practicum/filmorate/model/Buffer.java new file mode 100644 index 0000000..97ce14b --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Buffer.java @@ -0,0 +1,41 @@ +package ru.yandex.practicum.filmorate.model; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jdk.jfr.Description; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDate; +import java.util.*; + +@Data +@Builder +@AllArgsConstructor(staticName = "of") +public class Buffer { + private Long id; + @NotNull + @NotBlank + private String name; + @Description("New film update description") + private String description; + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate releaseDate; + @NotNull + private Integer duration; + private List genres; + private Long mpa; + + public Map toMapBuffer() { + Map values = new HashMap<>(); + values.put("id", id); + values.put("name", name); + values.put("description", description); + values.put("releaseDate", releaseDate); + values.put("duration", duration); + values.put("ratingId", mpa); + return values; + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java index cf96ab1..034e5de 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -1,34 +1,35 @@ package ru.yandex.practicum.filmorate.model; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Positive; -import jakarta.validation.constraints.Size; +import jdk.jfr.Description; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; import java.time.LocalDate; -import java.util.HashSet; -import java.util.Set; +import java.util.*; -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter +@Data +@Builder +@EqualsAndHashCode(of = {"id"}) +@AllArgsConstructor(staticName = "of") public class Film { private Long id; - - @NotBlank(message = "Название фильма не может быть пустым") + @NotNull + @NotBlank private String name; - - @Size(max = 200, message = "Описание фильма не может превышать 200 символов") + @Description("New film update description") private String description; - - @NotNull(message = "Дата релиза фильма не может быть null") + @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate releaseDate; - - @NotNull(message = "Продолжительность фильма должна быть указана") - @Positive(message = "Film duration must be a positive number") - private int duration; - - private Set likedUsers = new HashSet<>(); + @NotNull + private Integer duration; + @JsonIgnore + private Set likedUsers; + private Long mpa; + private LinkedHashSet genres; } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/FilmRequest.java b/src/main/java/ru/yandex/practicum/filmorate/model/FilmRequest.java new file mode 100644 index 0000000..7ceac23 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/FilmRequest.java @@ -0,0 +1,35 @@ +package ru.yandex.practicum.filmorate.model; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jdk.jfr.Description; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDate; +import java.util.*; + +@Data +@Builder +@EqualsAndHashCode(of = {"id"}) +@AllArgsConstructor(staticName = "of") +public class FilmRequest { + private Long id; + @NotNull + @NotBlank + private String name; + @Description("New film update description") + private String description; + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate releaseDate; + @NotNull + private Integer duration; + @JsonIgnore + private Set likedUsers; + private Mpa mpa; + private LinkedHashSet genres; +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/FriendRequest.java b/src/main/java/ru/yandex/practicum/filmorate/model/FriendRequest.java new file mode 100644 index 0000000..e713a4d --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/FriendRequest.java @@ -0,0 +1,15 @@ +package ru.yandex.practicum.filmorate.model; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.RequiredArgsConstructor; + +@Data +@RequiredArgsConstructor(staticName = "of") +public class FriendRequest { + @NotNull + private Long id; + private Long userId; + private Long friendId; + private boolean accept = false; +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java new file mode 100644 index 0000000..2d9e49c --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java @@ -0,0 +1,13 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(of = {"id"}) +@AllArgsConstructor(staticName = "of") +public class Genre { + Long id; + String name; +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/GenreConstant.java b/src/main/java/ru/yandex/practicum/filmorate/model/GenreConstant.java new file mode 100644 index 0000000..0c0d9ca --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/GenreConstant.java @@ -0,0 +1,13 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(of = {"id"}) +@AllArgsConstructor(staticName = "of") +public class GenreConstant { + private Long id; + private String name; +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java new file mode 100644 index 0000000..b2f95c9 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java @@ -0,0 +1,13 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(of = {"id"}) +@AllArgsConstructor(staticName = "of") +public class Mpa { + Long id; + String name; +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/MpaConstant.java b/src/main/java/ru/yandex/practicum/filmorate/model/MpaConstant.java new file mode 100644 index 0000000..e045398 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/MpaConstant.java @@ -0,0 +1,13 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(of = {"id"}) +@AllArgsConstructor(staticName = "of") +public class MpaConstant { + private Long id; + private String name; +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/User.java b/src/main/java/ru/yandex/practicum/filmorate/model/User.java index 2cdf9e4..0bec4f5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/User.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/User.java @@ -1,40 +1,42 @@ package ru.yandex.practicum.filmorate.model; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; +import lombok.*; import java.time.LocalDate; -import java.util.HashSet; +import java.util.HashMap; +import java.util.Map; import java.util.Set; @Data +@Builder @EqualsAndHashCode(of = {"email"}) @AllArgsConstructor(staticName = "of") public class User { private Long id; private String name; - @Email(message = "Invalid email") - @NotBlank(message = "Email cannot be empty") + @Email private String email; - @NotNull(message = "Login cannot be null") - @NotBlank(message = "Login cannot be empty or contain spaces") + @NotNull + @NotBlank private String login; @JsonFormat(pattern = "yyyy-MM-dd") - @NotNull(message = "Birthday cannot be null") private LocalDate birthday; - private Set friends; + @JsonIgnore + private Set friendRequests; - public Set getFriends() { - return friends == null ? new HashSet<>() : friends; // Защита от null - } - - public void setFriends(Set friends) { - this.friends = friends == null ? new HashSet<>() : friends; // Защита от null + public Map toMapUser() { + Map values = new HashMap<>(); + values.put("id", id); + values.put("name", name); + values.put("email", email); + values.put("login", login); + values.put("birthday", birthday); + return values; } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java new file mode 100644 index 0000000..28137a1 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -0,0 +1,161 @@ +package ru.yandex.practicum.filmorate.storage.film; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.exception.ExceptionMessages; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.exception.ValidationException; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.storage.user.UserStorage; + +import java.time.LocalDate; +import java.util.*; + +@Component +@RequiredArgsConstructor +@Slf4j +public class FilmDbStorage implements FilmStorage { + + private final JdbcTemplate jdbcTemplate; + private final UserStorage userStorage; + + // SQL-запросы + private static final String FIND_ALL_FILMS = "SELECT * FROM films"; + private static final String FIND_FILM_BY_ID = "SELECT * FROM films WHERE id = ?"; + private static final String INSERT_FILM = "INSERT INTO films (name, description, release_date, duration) VALUES (?, ?, ?, ?)"; + private static final String UPDATE_FILM = "UPDATE films SET name = ?, description = ?, release_date = ?, duration = ? WHERE id = ?"; + private static final String ADD_LIKE = "INSERT INTO likes (film_id, user_id) VALUES (?, ?)"; + private static final String REMOVE_LIKE = "DELETE FROM likes WHERE film_id = ? AND user_id = ?"; + private static final String GET_TOP_FILMS = "SELECT f.* FROM films f LEFT JOIN likes l ON f.id = l.film_id GROUP BY f.id ORDER BY COUNT(l.user_id) DESC LIMIT ?"; + + // Метод для отображения строки из результата запроса в объект Film + private static final RowMapper FILM_ROW_MAPPER = (rs, rowNum) -> Film.builder() + .id(rs.getLong("id")) + .name(rs.getString("name")) + .description(rs.getString("description")) + .releaseDate(rs.getDate("release_date").toLocalDate()) + .duration(rs.getInt("duration")) + .likedUsers(new HashSet<>()) // Лайки будут загружаться отдельно + .build(); + + @Override + public Collection findAll() { + log.info("Processing Get-request..."); + return jdbcTemplate.query(FIND_ALL_FILMS, FILM_ROW_MAPPER); + } + + @Override + public Film findById(Long id) throws NotFoundException { + if (id == null) { + throw new ValidationException(ExceptionMessages.FILM_ID_CANNOT_BE_NULL); + } + try { + return jdbcTemplate.queryForObject(FIND_FILM_BY_ID, FILM_ROW_MAPPER, id); + } catch (DataAccessException e) { + throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, id)); + } + } + + @Override + public Film create(Film film) throws ValidationException { + validateFilm(film); + + SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate) + .withTableName("films") + .usingGeneratedKeyColumns("id"); + Map parameters = Map.of( + "name", film.getName(), + "description", film.getDescription(), + "release_date", film.getReleaseDate(), + "duration", film.getDuration() + ); + long filmId = insert.executeAndReturnKey(parameters).longValue(); + film.setId(filmId); + + log.info("Film created: {}", film); + return findById(filmId); + } + + @Override + public Film update(Film film) throws NotFoundException, ValidationException { + validateFilm(film); + + if (!existsById(film.getId())) { + throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, film.getId())); + } + + int rowsAffected = jdbcTemplate.update(UPDATE_FILM, + film.getName(), + film.getDescription(), + film.getReleaseDate(), + film.getDuration(), + film.getId()); + + if (rowsAffected == 0) { + throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, film.getId())); + } + + log.info("Film with ID = {} updated: {}", film.getId(), film); + return findById(film.getId()); + } + + @Override + public void addLike(Long filmId, Long userId) throws NotFoundException { + if (!existsById(filmId)) { + throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId)); + } + if (userStorage.findById(userId) == null) { + throw new NotFoundException(String.format("User with ID = %d not found", userId)); + } + + jdbcTemplate.update(ADD_LIKE, filmId, userId); + log.info("User with ID = {} liked the film with ID = {}", userId, filmId); + } + + @Override + public void removeLike(Long filmId, Long userId) throws NotFoundException { + if (!existsById(filmId)) { + throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId)); + } + if (userStorage.findById(userId) == null) { + throw new NotFoundException(String.format("User with ID = %d not found", userId)); + } + + int rowsAffected = jdbcTemplate.update(REMOVE_LIKE, filmId, userId); + if (rowsAffected == 0) { + throw new NotFoundException(String.format("User with ID = %d did not like the film with ID = %d", userId, filmId)); + } + + log.info("User with ID = {} unliked the film with ID = {}", userId, filmId); + } + + @Override + public List getTopFilms(int count) { + log.info("Getting top-{} films by number of likes", count); + return jdbcTemplate.query(GET_TOP_FILMS, FILM_ROW_MAPPER, count); + } + + private boolean existsById(Long id) { + return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM films WHERE id = ?", Integer.class, id) > 0; + } + + private void validateFilm(Film film) throws ValidationException { + if (film.getName() == null || film.getName().isBlank()) { + throw new ValidationException(ExceptionMessages.FILM_NAME_CANNOT_BE_EMPTY); + } + if (film.getDescription() != null && film.getDescription().length() > 200) { + throw new ValidationException(ExceptionMessages.FILM_DESCRIPTION_TOO_LONG); + } + if (film.getReleaseDate() == null || film.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { + throw new ValidationException(ExceptionMessages.FILM_RELEASE_DATE_INVALID); + } + if (film.getDuration() <= 0) { + throw new ValidationException(ExceptionMessages.FILM_DURATION_INVALID); + } + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/InMemoryFilmStorage.java index f058161..144b7e2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/InMemoryFilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/InMemoryFilmStorage.java @@ -1,133 +1,133 @@ -package ru.yandex.practicum.filmorate.storage.film; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import ru.yandex.practicum.filmorate.exception.ExceptionMessages; -import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.exception.ValidationException; -import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.model.User; -import ru.yandex.practicum.filmorate.storage.user.UserStorage; - -import java.time.LocalDateTime; -import java.time.chrono.ChronoLocalDate; -import java.util.*; -import java.util.stream.Collectors; - -@Component -@Slf4j -public class InMemoryFilmStorage implements FilmStorage { - - private static final Map films = new HashMap<>(); - private final UserStorage userStorage; - - @Autowired - public InMemoryFilmStorage(UserStorage userStorage) { - this.userStorage = userStorage; - } - - @Override - public Collection findAll() { - log.info("Processing Get-request..."); - return films.values(); - } - - @Override - public Film findById(Long id) throws NotFoundException { - if (id == null) { - throw new ValidationException(ExceptionMessages.FILM_ID_CANNOT_BE_NULL); - } - Film film = films.get(id); - if (film == null) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, id)); - } - return film; - } - - @Override - public Film create(Film film) throws ValidationException { - validateFilm(film); - film.setId(getNextId()); - films.put(film.getId(), film); - return film; - } - - @Override - public Film update(Film film) throws NotFoundException, ValidationException { - validateFilm(film); - Film oldFilm = films.get(film.getId()); - if (oldFilm == null) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, film.getId())); - } - oldFilm.setName(film.getName()); - oldFilm.setDescription(film.getDescription()); - oldFilm.setReleaseDate(film.getReleaseDate()); - oldFilm.setDuration(film.getDuration()); - return oldFilm; - } - - @Override - public void addLike(Long filmId, Long userId) throws NotFoundException { - Film film = findById(filmId); // Проверяем, существует ли фильм - if (film == null) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId)); - } - - User user = userStorage.findById(userId); - if (user == null) { - throw new NotFoundException(String.format("not found", userId)); - } - - film.getLikedUsers().add(userId); - log.info("User with ID = {} liked the film with ID = {}", userId, filmId); - } - - @Override - public void removeLike(Long filmId, Long userId) throws NotFoundException { - Film film = findById(filmId); - if (film == null) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId)); - } - - User user = userStorage.findById(userId); - if (user == null) { - throw new NotFoundException(String.format("not found", userId)); - } - - if (!film.getLikedUsers().contains(userId)) { - throw new NotFoundException(String.format("User with ID = %d did not like the film with ID = %d", userId, filmId)); - } - - film.getLikedUsers().remove(userId); - log.info("User with ID = {} unliked the film with ID = {}", userId, filmId); - } - - @Override - public List getTopFilms(int count) { - log.info("Getting top-{} films by number of likes", count); - return films.values().stream() - .sorted(Comparator.comparingInt(f -> -f.getLikedUsers().size())) - .limit(count) - .collect(Collectors.toList()); - } - - private long getNextId() { - return films.keySet().stream().mapToLong(id -> id).max().orElse(0) + 1; - } - - private void validateFilm(Film film) throws ValidationException { - if (film.getName() == null || film.getName().isBlank()) { - throw new ValidationException(ExceptionMessages.FILM_NAME_CANNOT_BE_EMPTY); - } - if (film.getDescription() != null && film.getDescription().length() > 200) { - throw new ValidationException(ExceptionMessages.FILM_DESCRIPTION_TOO_LONG); - } - if (film.getReleaseDate().isBefore(ChronoLocalDate.from(LocalDateTime.of(1895, 12, 28, 0, 0, 0)))) { - throw new ValidationException(ExceptionMessages.FILM_RELEASE_DATE_INVALID); - } - if (film.getDuration() <= 0) { - throw new ValidationException(ExceptionMessages.FILM_DURATION_INVALID); - } - } -} \ No newline at end of file +//package ru.yandex.practicum.filmorate.storage.film; +// +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.stereotype.Component; +//import ru.yandex.practicum.filmorate.exception.ExceptionMessages; +//import ru.yandex.practicum.filmorate.exception.NotFoundException; +//import ru.yandex.practicum.filmorate.exception.ValidationException; +//import ru.yandex.practicum.filmorate.model.Film; +//import ru.yandex.practicum.filmorate.model.User; +//import ru.yandex.practicum.filmorate.storage.user.UserStorage; +// +//import java.time.LocalDateTime; +//import java.time.chrono.ChronoLocalDate; +//import java.util.*; +//import java.util.stream.Collectors; +// +//@Component +//@Slf4j +//public class InMemoryFilmStorage implements FilmStorage { +// +// private static final Map films = new HashMap<>(); +// private final UserStorage userStorage; +// +// @Autowired +// public InMemoryFilmStorage(UserStorage userStorage) { +// this.userStorage = userStorage; +// } +// +// @Override +// public Collection findAll() { +// log.info("Processing Get-request..."); +// return films.values(); +// } +// +// @Override +// public Film findById(Long id) throws NotFoundException { +// if (id == null) { +// throw new ValidationException(ExceptionMessages.FILM_ID_CANNOT_BE_NULL); +// } +// Film film = films.get(id); +// if (film == null) { +// throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, id)); +// } +// return film; +// } +// +// @Override +// public Film create(Film film) throws ValidationException { +// validateFilm(film); +// film.setId(getNextId()); +// films.put(film.getId(), film); +// return film; +// } +// +// @Override +// public Film update(Film film) throws NotFoundException, ValidationException { +// validateFilm(film); +// Film oldFilm = films.get(film.getId()); +// if (oldFilm == null) { +// throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, film.getId())); +// } +// oldFilm.setName(film.getName()); +// oldFilm.setDescription(film.getDescription()); +// oldFilm.setReleaseDate(film.getReleaseDate()); +// oldFilm.setDuration(film.getDuration()); +// return oldFilm; +// } +// +// @Override +// public void addLike(Long filmId, Long userId) throws NotFoundException { +// Film film = findById(filmId); // Проверяем, существует ли фильм +// if (film == null) { +// throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId)); +// } +// +// User user = userStorage.findById(userId); +// if (user == null) { +// throw new NotFoundException(String.format("not found", userId)); +// } +// +// film.getLikedUsers().add(userId); +// log.info("User with ID = {} liked the film with ID = {}", userId, filmId); +// } +// +// @Override +// public void removeLike(Long filmId, Long userId) throws NotFoundException { +// Film film = findById(filmId); +// if (film == null) { +// throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId)); +// } +// +// User user = userStorage.findById(userId); +// if (user == null) { +// throw new NotFoundException(String.format("not found", userId)); +// } +// +// if (!film.getLikedUsers().contains(userId)) { +// throw new NotFoundException(String.format("User with ID = %d did not like the film with ID = %d", userId, filmId)); +// } +// +// film.getLikedUsers().remove(userId); +// log.info("User with ID = {} unliked the film with ID = {}", userId, filmId); +// } +// +// @Override +// public List getTopFilms(int count) { +// log.info("Getting top-{} films by number of likes", count); +// return films.values().stream() +// .sorted(Comparator.comparingInt(f -> -f.getLikedUsers().size())) +// .limit(count) +// .collect(Collectors.toList()); +// } +// +// private long getNextId() { +// return films.keySet().stream().mapToLong(id -> id).max().orElse(0) + 1; +// } +// +// private void validateFilm(Film film) throws ValidationException { +// if (film.getName() == null || film.getName().isBlank()) { +// throw new ValidationException(ExceptionMessages.FILM_NAME_CANNOT_BE_EMPTY); +// } +// if (film.getDescription() != null && film.getDescription().length() > 200) { +// throw new ValidationException(ExceptionMessages.FILM_DESCRIPTION_TOO_LONG); +// } +// if (film.getReleaseDate().isBefore(ChronoLocalDate.from(LocalDateTime.of(1895, 12, 28, 0, 0, 0)))) { +// throw new ValidationException(ExceptionMessages.FILM_RELEASE_DATE_INVALID); +// } +// if (film.getDuration() <= 0) { +// throw new ValidationException(ExceptionMessages.FILM_DURATION_INVALID); +// } +// } +//} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/InMemoryUserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/InMemoryUserStorage.java index fbcbdf5..91a2843 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/InMemoryUserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/InMemoryUserStorage.java @@ -1,183 +1,183 @@ -package ru.yandex.practicum.filmorate.storage.user; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; -import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; -import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.exception.ValidationException; -import ru.yandex.practicum.filmorate.model.User; - -import java.time.LocalDate; -import java.util.*; -import java.util.stream.Collectors; - -@Component -@Slf4j -public class InMemoryUserStorage implements UserStorage { - private final Map users = new HashMap<>(); - - @Override - public Collection findAll() { - log.info("Returning the list of users..."); - return users.values(); - } - - @Override - public User create(User user) throws ValidationException, DuplicatedDataException { - validateEmail(user.getEmail()); - validateLogin(user.getLogin()); - if (user.getName() == null || user.getName().isBlank()) { - user.setName(user.getLogin()); - } - validateBirthday(user.getBirthday()); - duplicateCheck(user); - user.setId(getNextId()); - user.setFriends(new HashSet<>()); - users.put(user.getId(), user); - log.info("User created: {}", user); - return user; - } - - @Override - public User update(User newUser) throws NotFoundException, ValidationException { - if (newUser.getId() == null) { - throw new ValidationException("User ID cannot be null"); - } - if (!users.containsKey(newUser.getId())) { - throw new NotFoundException("User with ID = " + newUser.getId() + " not found"); - } - User oldUser = users.get(newUser.getId()); - oldUser.setEmail(newUser.getEmail()); - oldUser.setLogin(newUser.getLogin()); - oldUser.setName(newUser.getName() != null ? newUser.getName() : newUser.getLogin()); - oldUser.setBirthday(newUser.getBirthday()); - - if (newUser.getFriends() == null) { - newUser.setFriends(new HashSet<>()); - } - oldUser.setFriends(new HashSet<>(newUser.getFriends())); - - users.put(oldUser.getId(), oldUser); - log.info("User with ID = {} updated: {}", oldUser.getId(), oldUser); - return oldUser; - } - - @Override - public User findById(Long id) throws NotFoundException { - if (id == null) { - throw new ValidationException("ID cannot be null"); - } - User user = users.get(id); - if (user == null) { - throw new NotFoundException("User with ID = " + id + " not found"); - } - log.info("User found: {}", user); - return user; - } - - @Override - public void addFriend(Long userId, Long friendId) throws NotFoundException { - User user = findById(userId); - User friend = findById(friendId); - - if (user.getFriends() == null) { - user.setFriends(new HashSet<>()); - } - if (friend.getFriends() == null) { - friend.setFriends(new HashSet<>()); - } - - user.getFriends().add(friendId); - friend.getFriends().add(userId); - - update(user); - update(friend); - - log.info("User with ID = {} added as a friend to user with ID = {}", friendId, userId); - } - - @Override - public User removeFriend(Long userId, Long friendId) throws NotFoundException { - User user = findById(userId); - User friend = findById(friendId); - - if (user.getFriends() == null) { - user.setFriends(new HashSet<>()); - } - if (friend.getFriends() == null) { - friend.setFriends(new HashSet<>()); - } - - user.getFriends().remove(friendId); - friend.getFriends().remove(userId); - - log.info("User with ID = {} has been removed from friends of user with ID = {}", friendId, userId); - return user; - } - - @Override - public Collection getFriends(Long id) throws NotFoundException { - User user = findById(id); - - if (user.getFriends() == null || user.getFriends().isEmpty()) { - return Collections.emptyList(); - } - - return user.getFriends().stream() - .map(this::findById) - .collect(Collectors.toList()); - } - - @Override - public Collection getCommonFriends(Long userId, Long otherUserId) throws NotFoundException { - User user = findById(userId); - User otherUser = findById(otherUserId); - - if (user.getFriends() == null) { - user.setFriends(new HashSet<>()); - } - if (otherUser.getFriends() == null) { - otherUser.setFriends(new HashSet<>()); - } - - Set commonFriendIds = new HashSet<>(user.getFriends()); - commonFriendIds.retainAll(otherUser.getFriends()); - - return commonFriendIds.stream() - .map(this::findById) - .collect(Collectors.toList()); - } - - private long getNextId() { - return users.keySet().stream().mapToLong(id -> id).max().orElse(0) + 1; - } - - private void duplicateCheck(User user) throws DuplicatedDataException { - for (User u : users.values()) { - if (u.getEmail().equals(user.getEmail())) { - throw new DuplicatedDataException("A user with this email already exists"); - } - } - } - - private void validateEmail(String email) throws ValidationException { - if (email == null || email.isBlank() || !email.contains("@") || email.contains(" ") || email.length() < 2) { - throw new ValidationException("Invalid email"); - } - } - - private void validateLogin(String login) throws ValidationException { - if (login == null || login.isBlank() || login.contains(" ")) { - throw new ValidationException("Login cannot be empty or contain spaces"); - } - } - - private void validateBirthday(LocalDate birthday) throws ValidationException { - if (birthday == null) { - throw new ValidationException("Birthday cannot be null"); - } - if (birthday.isAfter(LocalDate.now())) { - throw new ValidationException("Birthday cannot be in the future"); - } - } -} \ No newline at end of file +//package ru.yandex.practicum.filmorate.storage.user; +// +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.stereotype.Component; +//import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; +//import ru.yandex.practicum.filmorate.exception.NotFoundException; +//import ru.yandex.practicum.filmorate.exception.ValidationException; +//import ru.yandex.practicum.filmorate.model.User; +// +//import java.time.LocalDate; +//import java.util.*; +//import java.util.stream.Collectors; +// +//@Component +//@Slf4j +//public class InMemoryUserStorage implements UserStorage { +// private final Map users = new HashMap<>(); +// +// @Override +// public Collection findAll() { +// log.info("Returning the list of users..."); +// return users.values(); +// } +// +// @Override +// public User create(User user) throws ValidationException, DuplicatedDataException { +// validateEmail(user.getEmail()); +// validateLogin(user.getLogin()); +// if (user.getName() == null || user.getName().isBlank()) { +// user.setName(user.getLogin()); +// } +// validateBirthday(user.getBirthday()); +// duplicateCheck(user); +// user.setId(getNextId()); +// user.setFriends(new HashSet<>()); +// users.put(user.getId(), user); +// log.info("User created: {}", user); +// return user; +// } +// +// @Override +// public User update(User newUser) throws NotFoundException, ValidationException { +// if (newUser.getId() == null) { +// throw new ValidationException("User ID cannot be null"); +// } +// if (!users.containsKey(newUser.getId())) { +// throw new NotFoundException("User with ID = " + newUser.getId() + " not found"); +// } +// User oldUser = users.get(newUser.getId()); +// oldUser.setEmail(newUser.getEmail()); +// oldUser.setLogin(newUser.getLogin()); +// oldUser.setName(newUser.getName() != null ? newUser.getName() : newUser.getLogin()); +// oldUser.setBirthday(newUser.getBirthday()); +// +// if (newUser.getFriends() == null) { +// newUser.setFriends(new HashSet<>()); +// } +// oldUser.setFriends(new HashSet<>(newUser.getFriends())); +// +// users.put(oldUser.getId(), oldUser); +// log.info("User with ID = {} updated: {}", oldUser.getId(), oldUser); +// return oldUser; +// } +// +// @Override +// public User findById(Long id) throws NotFoundException { +// if (id == null) { +// throw new ValidationException("ID cannot be null"); +// } +// User user = users.get(id); +// if (user == null) { +// throw new NotFoundException("User with ID = " + id + " not found"); +// } +// log.info("User found: {}", user); +// return user; +// } +// +// @Override +// public void addFriend(Long userId, Long friendId) throws NotFoundException { +// User user = findById(userId); +// User friend = findById(friendId); +// +// if (user.getFriends() == null) { +// user.setFriends(new HashSet<>()); +// } +// if (friend.getFriends() == null) { +// friend.setFriends(new HashSet<>()); +// } +// +// user.getFriends().add(friendId); +// friend.getFriends().add(userId); +// +// update(user); +// update(friend); +// +// log.info("User with ID = {} added as a friend to user with ID = {}", friendId, userId); +// } +// +// @Override +// public User removeFriend(Long userId, Long friendId) throws NotFoundException { +// User user = findById(userId); +// User friend = findById(friendId); +// +// if (user.getFriends() == null) { +// user.setFriends(new HashSet<>()); +// } +// if (friend.getFriends() == null) { +// friend.setFriends(new HashSet<>()); +// } +// +// user.getFriends().remove(friendId); +// friend.getFriends().remove(userId); +// +// log.info("User with ID = {} has been removed from friends of user with ID = {}", friendId, userId); +// return user; +// } +// +// @Override +// public Collection getFriends(Long id) throws NotFoundException { +// User user = findById(id); +// +// if (user.getFriends() == null || user.getFriends().isEmpty()) { +// return Collections.emptyList(); +// } +// +// return user.getFriends().stream() +// .map(this::findById) +// .collect(Collectors.toList()); +// } +// +// @Override +// public Collection getCommonFriends(Long userId, Long otherUserId) throws NotFoundException { +// User user = findById(userId); +// User otherUser = findById(otherUserId); +// +// if (user.getFriends() == null) { +// user.setFriends(new HashSet<>()); +// } +// if (otherUser.getFriends() == null) { +// otherUser.setFriends(new HashSet<>()); +// } +// +// Set commonFriendIds = new HashSet<>(user.getFriends()); +// commonFriendIds.retainAll(otherUser.getFriends()); +// +// return commonFriendIds.stream() +// .map(this::findById) +// .collect(Collectors.toList()); +// } +// +// private long getNextId() { +// return users.keySet().stream().mapToLong(id -> id).max().orElse(0) + 1; +// } +// +// private void duplicateCheck(User user) throws DuplicatedDataException { +// for (User u : users.values()) { +// if (u.getEmail().equals(user.getEmail())) { +// throw new DuplicatedDataException("A user with this email already exists"); +// } +// } +// } +// +// private void validateEmail(String email) throws ValidationException { +// if (email == null || email.isBlank() || !email.contains("@") || email.contains(" ") || email.length() < 2) { +// throw new ValidationException("Invalid email"); +// } +// } +// +// private void validateLogin(String login) throws ValidationException { +// if (login == null || login.isBlank() || login.contains(" ")) { +// throw new ValidationException("Login cannot be empty or contain spaces"); +// } +// } +// +// private void validateBirthday(LocalDate birthday) throws ValidationException { +// if (birthday == null) { +// throw new ValidationException("Birthday cannot be null"); +// } +// if (birthday.isAfter(LocalDate.now())) { +// throw new ValidationException("Birthday cannot be in the future"); +// } +// } +//} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java new file mode 100644 index 0000000..881414d --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -0,0 +1,213 @@ +package ru.yandex.practicum.filmorate.storage.user; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.exception.ValidationException; +import ru.yandex.practicum.filmorate.model.User; + + +import java.time.LocalDate; +import java.util.*; +import java.util.stream.Collectors; + +@Component +@RequiredArgsConstructor +@Slf4j +public class UserDbStorage implements UserStorage { + + private final JdbcTemplate jdbcTemplate; + + // SQL-запросы + private static final String FIND_ALL_USERS = "SELECT * FROM users"; + private static final String FIND_USER_BY_ID = "SELECT * FROM users WHERE id = ?"; + private static final String INSERT_USER = "INSERT INTO users (email, login, name, birthday) VALUES (?, ?, ?, ?)"; + private static final String UPDATE_USER = "UPDATE users SET email = ?, login = ?, name = ?, birthday = ? WHERE id = ?"; + private static final String ADD_FRIEND = "INSERT INTO friends (user_id, friend_id) VALUES (?, ?)"; + private static final String REMOVE_FRIEND = "DELETE FROM friends WHERE user_id = ? AND friend_id = ?"; + private static final String GET_FRIENDS = "SELECT u.* FROM users u JOIN friends f ON u.id = f.friend_id WHERE f.user_id = ?"; + private static final String CHECK_DUPLICATE_EMAIL = "SELECT COUNT(*) FROM users WHERE email = ?"; + + // Метод для отображения строки из результата запроса в объект User + private static final RowMapper USER_ROW_MAPPER = (rs, rowNum) -> User.builder() + .id(rs.getLong("id")) + .email(rs.getString("email")) + .login(rs.getString("login")) + .name(rs.getString("name")) + .birthday(rs.getDate("birthday").toLocalDate()) + .friends(new HashSet<>()) + .build(); + + @Override + public Collection findAll() { + log.info("Returning the list of users from the database..."); + return jdbcTemplate.query(FIND_ALL_USERS, USER_ROW_MAPPER); + } + + @Override + public User create(User user) throws ValidationException, DuplicatedDataException { + validateEmail(user.getEmail()); + validateLogin(user.getLogin()); + if (user.getName() == null || user.getName().isBlank()) { + user.setName(user.getLogin()); + } + validateBirthday(user.getBirthday()); + + // Проверка на дублирование email + if (jdbcTemplate.queryForObject(CHECK_DUPLICATE_EMAIL, Integer.class, user.getEmail()) > 0) { + throw new DuplicatedDataException("A user with this email already exists"); + } + + // Вставка нового пользователя в базу данных + SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate) + .withTableName("users") + .usingGeneratedKeyColumns("id"); + Map parameters = Map.of( + "email", user.getEmail(), + "login", user.getLogin(), + "name", user.getName(), + "birthday", user.getBirthday() + ); + long userId = insert.executeAndReturnKey(parameters).longValue(); + user.setId(userId); + + log.info("User created: {}", user); + return findById(userId); + } + + @Override + public User update(User newUser) throws NotFoundException, ValidationException { + if (newUser.getId() == null) { + throw new ValidationException("User ID cannot be null"); + } + if (!existsById(newUser.getId())) { + throw new NotFoundException("User with ID = " + newUser.getId() + " not found"); + } + + validateEmail(newUser.getEmail()); + validateLogin(newUser.getLogin()); + validateBirthday(newUser.getBirthday()); + + // Обновление пользователя в базе данных + int rowsAffected = jdbcTemplate.update(UPDATE_USER, + newUser.getEmail(), + newUser.getLogin(), + newUser.getName(), + newUser.getBirthday(), + newUser.getId()); + + if (rowsAffected == 0) { + throw new NotFoundException("User with ID = " + newUser.getId() + " not found"); + } + + log.info("User with ID = {} updated: {}", newUser.getId(), newUser); + return findById(newUser.getId()); + } + + @Override + public User findById(Long id) throws NotFoundException { + if (id == null) { + throw new ValidationException("ID cannot be null"); + } + try { + return jdbcTemplate.queryForObject(FIND_USER_BY_ID, USER_ROW_MAPPER, id); + } catch (DataAccessException e) { + throw new NotFoundException("User with ID = " + id + " not found"); + } + } + + @Override + public void addFriend(Long userId, Long friendId) throws NotFoundException { + if (!existsById(userId)) { + throw new NotFoundException("User with ID = " + userId + " not found"); + } + if (!existsById(friendId)) { + throw new NotFoundException("User with ID = " + friendId + " not found"); + } + + // Добавление друга + jdbcTemplate.update(ADD_FRIEND, userId, friendId); + log.info("User with ID = {} added as a friend to user with ID = {}", friendId, userId); + } + + @Override + public User removeFriend(Long userId, Long friendId) throws NotFoundException { + if (!existsById(userId)) { + throw new NotFoundException("User with ID = " + userId + " not found"); + } + if (!existsById(friendId)) { + throw new NotFoundException("User with ID = " + friendId + " not found"); + } + + // Удаление друга + jdbcTemplate.update(REMOVE_FRIEND, userId, friendId); + log.info("User with ID = {} has been removed from friends of user with ID = {}", friendId, userId); + return findById(userId); + } + + @Override + public Collection getFriends(Long id) throws NotFoundException { + if (!existsById(id)) { + throw new NotFoundException("User with ID = " + id + " not found"); + } + + return jdbcTemplate.query(GET_FRIENDS, USER_ROW_MAPPER, id); + } + + @Override + public Collection getCommonFriends(Long userId, Long otherUserId) throws NotFoundException { + if (!existsById(userId)) { + throw new NotFoundException("User with ID = " + userId + " not found"); + } + if (!existsById(otherUserId)) { + throw new NotFoundException("User with ID = " + otherUserId + " not found"); + } + + // Получение общих друзей + Set userFriends = getFriendIds(userId); + Set otherUserFriends = getFriendIds(otherUserId); + + userFriends.retainAll(otherUserFriends); + + return userFriends.stream() + .map(this::findById) + .collect(Collectors.toList()); + } + + private boolean existsById(Long id) { + return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users WHERE id = ?", Integer.class, id) > 0; + } + + private Set getFriendIds(Long userId) { + return jdbcTemplate.queryForList("SELECT friend_id FROM friends WHERE user_id = ?", Long.class, userId) + .stream() + .collect(Collectors.toSet()); + } + + private void validateEmail(String email) throws ValidationException { + if (email == null || email.isBlank() || !email.contains("@") || email.contains(" ") || email.length() < 2) { + throw new ValidationException("Invalid email"); + } + } + + private void validateLogin(String login) throws ValidationException { + if (login == null || login.isBlank() || login.contains(" ")) { + throw new ValidationException("Login cannot be empty or contain spaces"); + } + } + + private void validateBirthday(LocalDate birthday) throws ValidationException { + if (birthday == null) { + throw new ValidationException("Birthday cannot be null"); + } + if (birthday.isAfter(LocalDate.now())) { + throw new ValidationException("Birthday cannot be in the future"); + } + } +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b13789..533c651 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,6 @@ - +#logging.level.org.zalando.logbook=TRACE +spring.sql.init.mode=always +spring.datasource.url=jdbc:h2:file:./db/filmorate +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=password diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 0000000..f56133d --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1,15 @@ +INSERT INTO filmrating (rating) + VALUES + ('G'), + ('PG'), + ('PG-13'), + ('R'), + ('NC-17'); +INSERT INTO genre (name) + VALUES + ('Комедия'), + ('Драма'), + ('Мультфильм'), + ('Триллер'), + ('Документальный'), + ('Боевик'); \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 0000000..c1544fe --- /dev/null +++ b/src/main/resources/schema.sql @@ -0,0 +1,58 @@ +CREATE TABLE IF NOT EXISTS filmrating ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + rating Varchar NOT NULL +); + +CREATE TABLE IF NOT EXISTS film ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name Varchar NOT NULL, + description Varchar NOT NULL, + releaseDate Date, + duration INT, + ratingId BIGINT NOT NULL, + FOREIGN KEY (ratingId) REFERENCES filmrating (id) +); + +CREATE TABLE IF NOT EXISTS genre ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name Varchar NOT NULL +); + +CREATE TABLE IF NOT EXISTS filmGenre ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + filmId BIGINT NOT NULL, + genreId BIGINT NOT NULL, + FOREIGN KEY (genreId) REFERENCES genre (id), + FOREIGN KEY (filmId) REFERENCES film (id) +); + +CREATE TABLE IF NOT EXISTS users ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name Varchar NOT NULL, + email Varchar NOT NULL, + login Varchar NOT NULL, + birthday Date +); + +CREATE TABLE IF NOT EXISTS friends ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + userId BIGINT NOT NULL, + friendId BIGINT NOT NULL, + FOREIGN KEY (userId) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS friendRequest ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + userId BIGINT NOT NULL, + friendId BIGINT NOT NULL, + accept BOOLEAN, + FOREIGN KEY (userId) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS likedUsers ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + filmId BIGINT NOT NULL, + userId BIGINT NOT NULL, + FOREIGN KEY (filmId) REFERENCES film (id), + FOREIGN KEY (userId) REFERENCES users (id) +); \ No newline at end of file diff --git a/src/main/resources/schema.sql.bak b/src/main/resources/schema.sql.bak new file mode 100644 index 0000000..f1d7d94 --- /dev/null +++ b/src/main/resources/schema.sql.bak @@ -0,0 +1,51 @@ +CREATE TABLE IF NOT EXISTS filmrating ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + rating Varchar NOT NULL + ); + CREATE TABLE IF NOT EXISTS film ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name Varchar NOT NULL, + description Varchar NOT NULL, + releaseDate Date, + duration INT, + rating_id BIGINT NOT NULL, + FOREIGN KEY (rating_id) REFERENCES filmrating (id) + ); + CREATE TABLE IF NOT EXISTS genre ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name Varchar NOT NULL + ); + CREATE TABLE IF NOT EXISTS filmGenre ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + filmId BIGINT NOT NULL, + genreId BIGINT NOT NULL, + FOREIGN KEY (genreId) REFERENCES genre (id), + FOREIGN KEY (filmId) REFERENCES film (id) + ); + CREATE TABLE IF NOT EXISTS users ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name Varchar NOT NULL, + email Varchar NOT NULL, + login Varchar NOT NULL, + birthday Date + ); + CREATE TABLE IF NOT EXISTS friends ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + userId BIGINT NOT NULL, + friendId BIGINT NOT NULL, + FOREIGN KEY (userId) REFERENCES users (id) + ); + CREATE TABLE IF NOT EXISTS friendRequest ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + userId BIGINT NOT NULL, + friendId BIGINT NOT NULL, + accept BOOLEAN, + FOREIGN KEY (userId) REFERENCES users (id) + ); + CREATE TABLE IF NOT EXISTS likedUsers ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + filmId BIGINT NOT NULL, + userId BIGINT NOT NULL, + FOREIGN KEY (filmId) REFERENCES film (id), + FOREIGN KEY (userId) REFERENCES users (id) + ); \ No newline at end of file diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTest.java deleted file mode 100644 index 1e3ef4e..0000000 --- a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTest.java +++ /dev/null @@ -1,126 +0,0 @@ -package ru.yandex.practicum.filmorate; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.exception.ValidationException; -import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.service.FilmService; -import ru.yandex.practicum.filmorate.controller.FilmController; -import ru.yandex.practicum.filmorate.storage.film.FilmStorage; -import ru.yandex.practicum.filmorate.storage.film.InMemoryFilmStorage; -import ru.yandex.practicum.filmorate.storage.user.UserStorage; - -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; - -import static org.junit.jupiter.api.Assertions.*; - -public class FilmControllerTest { - - private static FilmController filmController; - private static Film validFilm; - private static Film invalidFilmName; - private static Film invalidFilmDescription; - private static Film invalidFilmReleaseDate; - private static Film filmWithNoId; - private static Film filmWithWrongId; - - @BeforeAll - public static void start() throws ValidationException { - // Создаем мок для UserStorage - UserStorage userStorage = Mockito.mock(UserStorage.class); - - // Создаем экземпляр хранилища фильмов, передавая мок UserStorage - FilmStorage filmStorage = new InMemoryFilmStorage(userStorage); - - // Создаем экземпляр сервиса, передавая ему хранилище - FilmService filmService = new FilmService(filmStorage); - - // Создаем контроллер, передавая ему сервис - filmController = new FilmController(filmService); - - // Инициализация тестовых данных - validFilm = new Film(); - validFilm.setId(0L); - validFilm.setName("Фильм"); - validFilm.setDescription("Описание"); - validFilm.setReleaseDate(LocalDate.parse("2020-04-19", DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - validFilm.setDuration(100); - filmController.createFilm(validFilm); - - invalidFilmName = new Film(); - invalidFilmName.setId(0L); - invalidFilmName.setName(" "); - invalidFilmName.setDescription("Описание фильма без имени"); - invalidFilmName.setReleaseDate(LocalDate.parse("2020-04-19", DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - invalidFilmName.setDuration(100); - - invalidFilmDescription = new Film(); - invalidFilmDescription.setId(0L); - invalidFilmDescription.setName("Название фильма"); - invalidFilmDescription.setDescription("Длинное длинное очень длинное описание " + - "Чтобы проверить, как это все дело работает"); - invalidFilmDescription.setReleaseDate(LocalDate.parse("2020-04-19", DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - invalidFilmDescription.setDuration(100); - - invalidFilmReleaseDate = new Film(); - invalidFilmReleaseDate.setId(0L); - invalidFilmReleaseDate.setName("Фильм с неправильной датой"); - invalidFilmReleaseDate.setDescription("Описание фильма с неправильной датой"); - invalidFilmReleaseDate.setReleaseDate(LocalDate.parse("1880-04-19", DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - invalidFilmReleaseDate.setDuration(100); - - filmWithNoId = new Film(); - filmWithNoId.setId(null); - filmWithNoId.setName("Фильм без айди"); - filmWithNoId.setDescription("Описание фильма без айди"); - filmWithNoId.setReleaseDate(LocalDate.parse("2020-04-19", DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - filmWithNoId.setDuration(100); - - filmWithWrongId = new Film(); - filmWithWrongId.setId(50L); - filmWithWrongId.setName("Фильм с неправильным айди"); - filmWithWrongId.setDescription("Описание фильма с неправильным айди"); - filmWithWrongId.setReleaseDate(LocalDate.parse("2020-04-19", DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - filmWithWrongId.setDuration(100); - } - - @Test - public void shouldCreateValidFilm() throws ValidationException { - assertEquals(filmController.createFilm(validFilm), validFilm); - } - - @Test - public void shouldThrowExceptionWhenCreatingFilmWithEmptyName() { - ValidationException exception = assertThrows(ValidationException.class, () -> { - filmController.createFilm(invalidFilmName); - }); - assertNotNull(exception); - assertEquals("Film name cannot be empty", exception.getMessage()); - } - - @Test - public void shouldThrowExceptionWhenCreatingFilmWithOldReleaseDate() { - ValidationException exception = assertThrows(ValidationException.class, () -> { - filmController.createFilm(invalidFilmReleaseDate); - }); - assertNotNull(exception); - assertEquals("Film release date cannot be earlier than December 28, 1895", exception.getMessage()); - } - - @Test - public void shouldThrowExceptionWhenUpdatingFilmWithWrongId() { - NotFoundException exception = assertThrows(NotFoundException.class, () -> { - filmController.update(filmWithWrongId); - }); - assertNotNull(exception); - } - - @AfterAll - public static void shouldReturnAllFilms() { - assertNotNull(filmController.getFilms()); - } -} \ No newline at end of file diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmoRateApplicationTests.java b/src/test/java/ru/yandex/practicum/filmorate/FilmoRateApplicationTests.java new file mode 100644 index 0000000..92d1760 --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/FilmoRateApplicationTests.java @@ -0,0 +1,54 @@ +package ru.yandex.practicum.filmorate; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.storage.user.UserDbStorage; + +import java.time.LocalDate; +import java.util.HashSet; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureTestDatabase +public class FilmoRateApplicationTests { + + @Autowired + private UserDbStorage userDbStorage; + + @Test + public void testFindUserById() throws NotFoundException { + // Создаем пользователя через метод of + User user = User.of( + null, // ID будет сгенерирован базой данных + "Test User", + "test@example.com", + "testLogin", + LocalDate.of(1990, 1, 1), + new HashSet<>(), + new HashSet<>() + ); + + // Добавляем пользователя в базу данных + User createdUser = userDbStorage.create(user); + + // Проверяем, что пользователь с ID = createdUser.getId() существует в базе данных + User foundUser = userDbStorage.findById(createdUser.getId()); + + // Проверяем, что найденный пользователь соответствует ожидаемым значениям + assertThat(foundUser) + .isNotNull() + .hasFieldOrPropertyWithValue("id", createdUser.getId()) + .hasFieldOrPropertyWithValue("email", "test@example.com") + .hasFieldOrPropertyWithValue("login", "testLogin") + .hasFieldOrPropertyWithValue("name", "Test User") + .hasFieldOrPropertyWithValue("birthday", LocalDate.of(1990, 1, 1)); + } +} \ No newline at end of file diff --git a/src/test/java/ru/yandex/practicum/filmorate/InMemoryUserStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/InMemoryUserStorageTest.java deleted file mode 100644 index 9365e5c..0000000 --- a/src/test/java/ru/yandex/practicum/filmorate/InMemoryUserStorageTest.java +++ /dev/null @@ -1,95 +0,0 @@ -package ru.yandex.practicum.filmorate; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.model.User; -import ru.yandex.practicum.filmorate.storage.user.InMemoryUserStorage; - -import java.time.LocalDate; -import java.util.HashSet; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - -public class InMemoryUserStorageTest { - - private InMemoryUserStorage userStorage; - - @BeforeEach - public void setUp() { - userStorage = new InMemoryUserStorage(); - } - - @Test - public void shouldAddFriendAndUpdateBothUsers() throws Exception { - User user1 = User.of(null, "User 1", "user1@example.com", "user1", LocalDate.of(1990, 1, 1), new HashSet<>()); - User user2 = User.of(null, "User 2", "user2@example.com", "user2", LocalDate.of(1995, 5, 5), new HashSet<>()); - - userStorage.create(user1); - userStorage.create(user2); - - userStorage.addFriend(user1.getId(), user2.getId()); - - List friendsOfUser1 = (List) userStorage.getFriends(user1.getId()); - assertEquals(1, friendsOfUser1.size()); - assertEquals(user2.getId(), friendsOfUser1.get(0).getId()); - - List friendsOfUser2 = (List) userStorage.getFriends(user2.getId()); - assertEquals(1, friendsOfUser2.size()); - assertEquals(user1.getId(), friendsOfUser2.get(0).getId()); - } - - @Test - public void shouldRemoveFriendAndUpdateBothUsers() throws Exception { - User user1 = User.of(null, "User 1", "user1@example.com", "user1", LocalDate.of(1990, 1, 1), null); - User user2 = User.of(null, "User 2", "user2@example.com", "user2", LocalDate.of(1995, 5, 5), null); - - userStorage.create(user1); - userStorage.create(user2); - - userStorage.addFriend(user1.getId(), user2.getId()); - - userStorage.removeFriend(user1.getId(), user2.getId()); - - assertTrue(((List) userStorage.getFriends(user1.getId())).isEmpty()); - assertTrue(((List) userStorage.getFriends(user2.getId())).isEmpty()); - } - - @Test - public void shouldGetCommonFriends() throws Exception { - User user1 = User.of(null, "User 1", "user1@example.com", "user1", LocalDate.of(1990, 1, 1), new HashSet<>()); - User user2 = User.of(null, "User 2", "user2@example.com", "user2", LocalDate.of(1995, 5, 5), new HashSet<>()); - User user3 = User.of(null, "User 3", "user3@example.com", "user3", LocalDate.of(2000, 1, 1), new HashSet<>()); - - userStorage.create(user1); - userStorage.create(user2); - userStorage.create(user3); - - userStorage.addFriend(user1.getId(), user3.getId()); - userStorage.addFriend(user2.getId(), user3.getId()); - - List commonFriends = (List) userStorage.getCommonFriends(user1.getId(), user2.getId()); - - assertEquals(1, commonFriends.size()); - assertEquals(user3.getId(), commonFriends.get(0).getId()); - } - - @Test - public void shouldThrowNotFoundExceptionForUnknownUser() { - User user1 = User.of(null, "User 1", "user1@example.com", "user1", LocalDate.of(1990, 1, 1), new HashSet<>()); - userStorage.create(user1); - - NotFoundException exception = assertThrows(NotFoundException.class, () -> { - userStorage.addFriend(user1.getId(), 999L); - }); - assertNotNull(exception); - assertTrue(exception.getMessage().contains("not found")); - - exception = assertThrows(NotFoundException.class, () -> { - userStorage.removeFriend(user1.getId(), 999L); - }); - assertNotNull(exception); - assertTrue(exception.getMessage().contains("not found")); - } -} \ No newline at end of file diff --git a/src/test/java/ru/yandex/practicum/filmorate/UserControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/UserControllerTest.java deleted file mode 100644 index fa1fbe0..0000000 --- a/src/test/java/ru/yandex/practicum/filmorate/UserControllerTest.java +++ /dev/null @@ -1,100 +0,0 @@ -package ru.yandex.practicum.filmorate; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import ru.yandex.practicum.filmorate.exception.ValidationException; -import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; -import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.model.User; -import ru.yandex.practicum.filmorate.service.UserService; -import ru.yandex.practicum.filmorate.controller.UserController; -import ru.yandex.practicum.filmorate.storage.user.InMemoryUserStorage; -import ru.yandex.practicum.filmorate.storage.user.UserStorage; - -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.HashSet; - -import static org.junit.jupiter.api.Assertions.*; - -public class UserControllerTest { - - private static UserController userController; - private static User validUser; - private static User invalidEmailUser; - private static User duplicateEmailUser; - private static User invalidLoginUser; - private static User userWithNoId; - private static User userWithWrongId; - - @BeforeAll - public static void start() throws ValidationException, DuplicatedDataException { - UserStorage userStorage = new InMemoryUserStorage(); - userController = new UserController(new UserService(userStorage)); - - // Валидный пользователь - validUser = User.of(0L, "Valid User", "valid@mail.ru", "validLogin", LocalDate.parse("2000-01-01", DateTimeFormatter.ofPattern("yyyy-MM-dd")), new HashSet<>()); - userController.create(validUser); - - // Пользователь с некорректным email - invalidEmailUser = User.of(0L, "Invalid Email User", "invalidEmail", "invalidLogin", LocalDate.parse("2000-01-01", DateTimeFormatter.ofPattern("yyyy-MM-dd")), new HashSet<>()); - - // Пользователь с дублирующимся email - duplicateEmailUser = User.of(0L, "Duplicate Email User", "valid@mail.ru", "duplicateLogin", LocalDate.parse("2000-01-01", DateTimeFormatter.ofPattern("yyyy-MM-dd")), new HashSet<>()); - - // Пользователь с некорректным логином (с пробелами) - invalidLoginUser = User.of(0L, "Invalid Login User", "login@mail.ru", "invalid login", LocalDate.parse("2000-01-01", DateTimeFormatter.ofPattern("yyyy-MM-dd")), new HashSet<>()); - - // Пользователь без ID - userWithNoId = User.of(null, "No ID User", "noid@mail.ru", "noIdLogin", LocalDate.parse("2000-01-01", DateTimeFormatter.ofPattern("yyyy-MM-dd")), new HashSet<>()); - - // Пользователь с несуществующим ID - userWithWrongId = User.of(999L, "Wrong ID User", "wrongid@mail.ru", "wrongIdLogin", LocalDate.parse("2000-01-01", DateTimeFormatter.ofPattern("yyyy-MM-dd")), new HashSet<>()); - } - - @Test - public void shouldThrowExceptionWhenCreatingUserWithInvalidEmail() { - ValidationException exception = assertThrows(ValidationException.class, () -> { - userController.create(invalidEmailUser); - }); - assertNotNull(exception); - assertEquals("Invalid email", exception.getMessage()); - } - - @Test - public void shouldThrowExceptionWhenCreatingUserWithDuplicateEmail() { - DuplicatedDataException exception = assertThrows(DuplicatedDataException.class, () -> { - userController.create(duplicateEmailUser); - }); - assertNotNull(exception); - assertEquals("A user with this email already exists", exception.getMessage()); - } - - @Test - public void shouldThrowExceptionWhenCreatingUserWithInvalidLogin() { - ValidationException exception = assertThrows(ValidationException.class, () -> { - userController.create(invalidLoginUser); - }); - assertNotNull(exception); - assertEquals("Login cannot be empty or contain spaces", exception.getMessage()); - } - - - @Test - public void shouldThrowExceptionWhenUpdatingUserWithNoId() { - ValidationException exception = assertThrows(ValidationException.class, () -> { - userController.update(userWithNoId); - }); - assertNotNull(exception); - assertEquals("User ID cannot be null", exception.getMessage()); - } - - @Test - public void shouldThrowExceptionWhenUpdatingUserWithWrongId() { - NotFoundException exception = assertThrows(NotFoundException.class, () -> { - userController.update(userWithWrongId); - }); - assertNotNull(exception); - assertEquals("User with ID = 999 not found", exception.getMessage()); - } -} \ No newline at end of file diff --git a/src/test/java/ru/yandex/practicum/filmorate/UserDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/UserDbStorageTest.java new file mode 100644 index 0000000..1ccd44e --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/UserDbStorageTest.java @@ -0,0 +1,113 @@ +package ru.yandex.practicum.filmorate; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.jdbc.Sql; +import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.exception.ValidationException; +import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.storage.user.UserDbStorage; + +import java.time.LocalDate; +import java.util.Collection; +import java.util.HashSet; + +import static org.junit.jupiter.api.Assertions.*; + +@JdbcTest +@Sql(scripts = {"/schema.sql", "/data.sql"}) // Загружаем схему и тестовые данные +class UserDbStorageTest { + + @Autowired + private JdbcTemplate jdbcTemplate; + + private UserDbStorage userDbStorage; + + @BeforeEach + void setUp() { + userDbStorage = new UserDbStorage(jdbcTemplate); + } + + @Test + void testCreateUser() throws ValidationException, DuplicatedDataException { + // Создаем нового пользователя с использованием метода User.of(...) + User user = User.of( + null, + "Test User", + "test@example.com", + "testLogin", + LocalDate.of(1990, 1, 1), + new HashSet<>(), // Инициализируем пустое множество friends + new HashSet<>() // Инициализируем пустое множество friendRequests + ); + + User createdUser = userDbStorage.create(user); + + assertNotNull(createdUser.getId()); + assertEquals("test@example.com", createdUser.getEmail()); + assertEquals("testLogin", createdUser.getLogin()); + assertEquals("Test User", createdUser.getName()); + assertEquals(LocalDate.of(1990, 1, 1), createdUser.getBirthday()); + } + + @Test + void testUpdateUser() throws ValidationException, DuplicatedDataException, NotFoundException { + // Создаем нового пользователя с использованием метода User.of(...) + User user = User.of( + null, + "Test User", + "test@example.com", + "testLogin", + LocalDate.of(1990, 1, 1), + new HashSet<>(), + new HashSet<>() + ); + User createdUser = userDbStorage.create(user); + + // Обновляем пользователя с использованием метода User.of(...) + User updatedUser = User.of( + createdUser.getId(), + "Updated User", + "test@example.com", + "testLogin", + LocalDate.of(1990, 1, 1), + new HashSet<>(), + new HashSet<>() + ); + User result = userDbStorage.update(updatedUser); + + assertEquals("Updated User", result.getName()); + } + + @Test + void testFindById() throws ValidationException, DuplicatedDataException, NotFoundException { + // Создаем нового пользователя с использованием метода User.of(...) + User user = User.of( + null, + "Test User", + "test@example.com", + "testLogin", + LocalDate.of(1990, 1, 1), + new HashSet<>(), + new HashSet<>() + ); + User createdUser = userDbStorage.create(user); + + User foundUser = userDbStorage.findById(createdUser.getId()); + + assertEquals(createdUser.getId(), foundUser.getId()); + assertEquals("test@example.com", foundUser.getEmail()); + assertEquals("testLogin", foundUser.getLogin()); + assertEquals("Test User", foundUser.getName()); + assertEquals(LocalDate.of(1990, 1, 1), foundUser.getBirthday()); + } + + @Test + void testFindByIdNotFound() { + assertThrows(NotFoundException.class, () -> userDbStorage.findById(999L)); + } +} \ No newline at end of file From 752106b4ec0c2920e189190f34af251a82a8aac2 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 00:43:14 +0500 Subject: [PATCH 002/118] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=20?= =?UTF-8?q?=D1=84=D0=B0=D0=B9=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Docker.java | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 Docker.java diff --git a/Docker.java b/Docker.java deleted file mode 100644 index 7875079..0000000 --- a/Docker.java +++ /dev/null @@ -1,21 +0,0 @@ -# первый (вспомогательный) этап с именем builder -FROM amazoncorretto:22-alpine as builder -# устанавливаем application в качестве рабочей директории -WORKDIR application -# копируем артефакт в папку application в контейнере -COPY target/*.jar app.jar -# используем специальный режим запуска Spring Boot приложения, -# который активирует распаковку итогового jar-файла на составляющие -RUN java -Djarmode=layertools -jar app.jar extract - -# заключительный этап, создающий финальный образ -FROM amazoncorretto:22-alpine -# поочерёдно копируем необходимые для приложения файлы, -# которые были распакованы из артефакта на предыдущем этапе; -# при этом каждая инструкция COPY создаёт новый слой -COPY --from=builder /application/dependencies/ ./ -COPY --from=builder /application/spring-boot-loader/ ./ -COPY --from=builder /application/snapshot-dependencies/ ./ -COPY --from=builder /application/application ./ -# в качестве команды указываем запуск специального загрузчика -ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"] \ No newline at end of file From 61ca261aae9d863a8f7a249c362ebc03000a0738 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 00:45:16 +0500 Subject: [PATCH 003/118] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ru/yandex/practicum/filmorate/UserDbStorageTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/ru/yandex/practicum/filmorate/UserDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/UserDbStorageTest.java index 1ccd44e..d417fad 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/UserDbStorageTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/UserDbStorageTest.java @@ -13,7 +13,6 @@ import ru.yandex.practicum.filmorate.storage.user.UserDbStorage; import java.time.LocalDate; -import java.util.Collection; import java.util.HashSet; import static org.junit.jupiter.api.Assertions.*; From 70c62e79614a99c377e2575e1eb59cb5a10bd6d7 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 01:08:15 +0500 Subject: [PATCH 004/118] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/storage/user/UserDbStorage.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 881414d..8319e95 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -29,9 +29,9 @@ public class UserDbStorage implements UserStorage { private static final String FIND_USER_BY_ID = "SELECT * FROM users WHERE id = ?"; private static final String INSERT_USER = "INSERT INTO users (email, login, name, birthday) VALUES (?, ?, ?, ?)"; private static final String UPDATE_USER = "UPDATE users SET email = ?, login = ?, name = ?, birthday = ? WHERE id = ?"; - private static final String ADD_FRIEND = "INSERT INTO friends (user_id, friend_id) VALUES (?, ?)"; - private static final String REMOVE_FRIEND = "DELETE FROM friends WHERE user_id = ? AND friend_id = ?"; - private static final String GET_FRIENDS = "SELECT u.* FROM users u JOIN friends f ON u.id = f.friend_id WHERE f.user_id = ?"; + private static final String ADD_FRIEND = "INSERT INTO friends (userId, friendId) VALUES (?, ?)"; + private static final String REMOVE_FRIEND = "DELETE FROM friends WHERE userId = ? AND friendId = ?"; + private static final String GET_FRIENDS = "SELECT u.* FROM users u JOIN friends f ON u.id = f.friendId WHERE f.userId = ?"; private static final String CHECK_DUPLICATE_EMAIL = "SELECT COUNT(*) FROM users WHERE email = ?"; // Метод для отображения строки из результата запроса в объект User From 566820ac7f032dc44e180f132476e9685398ce5e Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 01:15:00 +0500 Subject: [PATCH 005/118] =?UTF-8?q?=D0=BF=D0=BE=D0=BC=D0=B5=D0=BD=D1=8F?= =?UTF-8?q?=D0=BB=D0=B0=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/storage/film/FilmDbStorage.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 28137a1..a3aeb9d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -29,9 +29,9 @@ public class FilmDbStorage implements FilmStorage { private static final String FIND_FILM_BY_ID = "SELECT * FROM films WHERE id = ?"; private static final String INSERT_FILM = "INSERT INTO films (name, description, release_date, duration) VALUES (?, ?, ?, ?)"; private static final String UPDATE_FILM = "UPDATE films SET name = ?, description = ?, release_date = ?, duration = ? WHERE id = ?"; - private static final String ADD_LIKE = "INSERT INTO likes (film_id, user_id) VALUES (?, ?)"; - private static final String REMOVE_LIKE = "DELETE FROM likes WHERE film_id = ? AND user_id = ?"; - private static final String GET_TOP_FILMS = "SELECT f.* FROM films f LEFT JOIN likes l ON f.id = l.film_id GROUP BY f.id ORDER BY COUNT(l.user_id) DESC LIMIT ?"; + private static final String ADD_LIKE = "INSERT INTO likes (filmID, userID) VALUES (?, ?)"; + private static final String REMOVE_LIKE = "DELETE FROM likes WHERE filmID = ? AND userID = ?"; + private static final String GET_TOP_FILMS = "SELECT f.* FROM films f LEFT JOIN likes l ON f.id = l.filmID GROUP BY f.id ORDER BY COUNT(l.userID) DESC LIMIT ?"; // Метод для отображения строки из результата запроса в объект Film private static final RowMapper FILM_ROW_MAPPER = (rs, rowNum) -> Film.builder() From b94fb113c750679a42ad5f85db765c459bbabcac Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 02:14:41 +0500 Subject: [PATCH 006/118] =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5?= =?UTF-8?q?=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 80 +++++++++++-------- .../practicum/filmorate/model/Film.java | 2 +- .../filmorate/storage/film/FilmStorage.java | 1 - 3 files changed, 48 insertions(+), 35 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index ef0a166..4dbea03 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,16 +1,17 @@ package ru.yandex.practicum.filmorate.controller; +import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import org.springframework.beans.factory.annotation.Autowired; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.service.FilmService; -import java.util.Collection; -import java.util.Map; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.*; @RestController @RequestMapping("/films") @@ -23,51 +24,64 @@ public FilmController(FilmService filmService) { this.filmService = filmService; } - //создание фильма - @PostMapping - public Film createFilm(@Valid @RequestBody Film film) { - return filmService.createFilm(film); + @GetMapping + public List findAll() { + return new ArrayList<>(filmService.getFilms()); } - //обновление фильма - @PutMapping - public Film update(@Valid @RequestBody Film film) { - return filmService.update(film); + @GetMapping("/{id}") + public Film findById(@PathVariable("id") Long id) throws NotFoundException { + return filmService.getFilmById(id); } - //получение всех фильмов - @GetMapping - public Collection getFilms() { - return filmService.getFilms(); + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public Film create(@Valid @RequestBody ObjectNode objectNode) throws NotFoundException { + Film film = parseFilmFromObjectNode(objectNode); + return filmService.createFilm(film); } - //получение фильма по ID - @GetMapping("/{id}") - public Film getFilmById(@PathVariable Long id) { - return filmService.getFilmById(id); + @PutMapping + public Film update(@Valid @RequestBody ObjectNode objectNode) throws NotFoundException { + Film film = parseFilmFromObjectNode(objectNode); + return filmService.update(film); } @PutMapping("/{id}/like/{userId}") - public ResponseEntity addLike(@PathVariable Long id, @PathVariable Long userId) { - try { - filmService.addLike(id, userId); - return ResponseEntity.ok().build(); // Возвращаем 200 OK, если лайк добавлен - } catch (NotFoundException e) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(Map.of("error", e.getMessage())); // Возвращаем 404 и JSON с ошибкой - } + public void addLike(@PathVariable("id") Long id, @PathVariable("userId") Long userId) throws NotFoundException { + filmService.addLike(id, userId); } - //удаление лайка из фильма @DeleteMapping("/{id}/like/{userId}") - public ResponseEntity removeLike(@PathVariable Long id, @PathVariable Long userId) { + public void delLike(@PathVariable("id") Long id, @PathVariable("userId") Long userId) throws NotFoundException { filmService.removeLike(id, userId); - return ResponseEntity.ok().build(); } - //получение популярных фильмов @GetMapping("/popular") - public Collection getTopFilms(@RequestParam(defaultValue = "10") int count) { + public List viewRaiting(@RequestParam(required = false, defaultValue = "10") int count) { return filmService.getTopFilms(count); } + + private Film parseFilmFromObjectNode(ObjectNode objectNode) { + Long id = objectNode.has("id") ? objectNode.get("id").asLong() : null; + String name = objectNode.get("name").asText(); + String description = objectNode.get("description").asText(); + LocalDate releaseDate = LocalDate.parse(objectNode.get("releaseDate").asText(), DateTimeFormatter.ofPattern("yyyy-MM-dd")); + Integer duration = objectNode.get("duration").asInt(); + Set likedUsers = new HashSet<>(); + Long mpaId = objectNode.get("mpa").get("id").asLong(); + LinkedHashSet genres = new LinkedHashSet<>(); // Используем LinkedHashSet + objectNode.get("genres").forEach(genre -> genres.add(genre.get("id").asLong())); + + return Film.builder() + .id(id) + .name(name) + .description(description) + .releaseDate(releaseDate) + .duration(duration) + .likedUsers(likedUsers) + .mpaId(mpaId) + .genres(genres) + .build(); + } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java index 034e5de..4ead6ec 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -30,6 +30,6 @@ public class Film { private Integer duration; @JsonIgnore private Set likedUsers; - private Long mpa; + private Long mpaId; private LinkedHashSet genres; } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java index a6f329d..5762564 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java @@ -16,7 +16,6 @@ public interface FilmStorage { Film update(Film film) throws NotFoundException; - //Film void addLike(Long filmId, Long userId) throws NotFoundException; void removeLike(Long filmId, Long userId) throws NotFoundException; From af1a96227e395b80469522171cdf855f5a98537c Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 03:06:40 +0500 Subject: [PATCH 007/118] =?UTF-8?q?=D0=BA=D1=83=D1=87=D0=B0=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 76 +++----- .../filmorate/controller/UserController.java | 57 +++--- .../exception/ConditionsNotMetException.java | 15 ++ .../exception/NotFoundException.java | 2 +- .../practicum/filmorate/model/Film.java | 21 +- .../filmorate/service/FilmInterface.java | 14 ++ .../filmorate/service/FilmService.java | 180 +++++++++++++++--- .../filmorate/service/UserInterface.java | 15 ++ .../filmorate/service/UserService.java | 106 ++++++++--- .../filmorate/storage/film/FilmDbStorage.java | 47 ++++- .../filmorate/storage/film/FilmStorage.java | 6 - .../filmorate/storage/user/UserDbStorage.java | 42 ++-- 12 files changed, 422 insertions(+), 159 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/exception/ConditionsNotMetException.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/FilmInterface.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/UserInterface.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 4dbea03..5410a92 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,87 +1,69 @@ package ru.yandex.practicum.filmorate.controller; -import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.service.FilmService; +import ru.yandex.practicum.filmorate.model.FilmRequest; +import ru.yandex.practicum.filmorate.service.FilmInterface; +import ru.yandex.practicum.filmorate.storage.film.FilmStorage; +import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.Collection; +import java.util.List; @RestController @RequestMapping("/films") + public class FilmController { - private final FilmService filmService; + private final FilmStorage filmStorage; + private final FilmInterface filmInterface; + private final UserStorage userStorage; @Autowired - public FilmController(FilmService filmService) { - this.filmService = filmService; + public FilmController(FilmStorage filmStorage, UserStorage userStorage, FilmInterface filmInterface) { + this.filmStorage = filmStorage; + this.userStorage = userStorage; + this.filmInterface = filmInterface; } @GetMapping - public List findAll() { - return new ArrayList<>(filmService.getFilms()); + public Collection findAll() { + return filmStorage.findAll(); } @GetMapping("/{id}") - public Film findById(@PathVariable("id") Long id) throws NotFoundException { - return filmService.getFilmById(id); + public Film findById(@PathVariable("id") Long id) throws ConditionsNotMetException, NotFoundException { + return filmStorage.findById(id); } @PostMapping @ResponseStatus(HttpStatus.CREATED) - public Film create(@Valid @RequestBody ObjectNode objectNode) throws NotFoundException { - Film film = parseFilmFromObjectNode(objectNode); - return filmService.createFilm(film); + public Film create(@Valid @RequestBody Film film) throws ConditionsNotMetException, NullPointerException { + return filmStorage.create(film); } @PutMapping - public Film update(@Valid @RequestBody ObjectNode objectNode) throws NotFoundException { - Film film = parseFilmFromObjectNode(objectNode); - return filmService.update(film); + public Film update(@Valid @RequestBody Film newFilm) throws ConditionsNotMetException, NotFoundException { + return filmStorage.update(newFilm); } @PutMapping("/{id}/like/{userId}") - public void addLike(@PathVariable("id") Long id, @PathVariable("userId") Long userId) throws NotFoundException { - filmService.addLike(id, userId); + public FilmRequest addLike(@Valid @RequestBody @PathVariable("id") Long id, @PathVariable("userId") Long userId) throws ConditionsNotMetException { + return filmInterface.addLike(userId, id); } @DeleteMapping("/{id}/like/{userId}") - public void delLike(@PathVariable("id") Long id, @PathVariable("userId") Long userId) throws NotFoundException { - filmService.removeLike(id, userId); + public FilmRequest delLike(@Valid @RequestBody @PathVariable("id") Long id, @PathVariable("userId") Long userId) throws NotFoundException { + return filmInterface.delLike(userId, id); } @GetMapping("/popular") - public List viewRaiting(@RequestParam(required = false, defaultValue = "10") int count) { - return filmService.getTopFilms(count); - } - - private Film parseFilmFromObjectNode(ObjectNode objectNode) { - Long id = objectNode.has("id") ? objectNode.get("id").asLong() : null; - String name = objectNode.get("name").asText(); - String description = objectNode.get("description").asText(); - LocalDate releaseDate = LocalDate.parse(objectNode.get("releaseDate").asText(), DateTimeFormatter.ofPattern("yyyy-MM-dd")); - Integer duration = objectNode.get("duration").asInt(); - Set likedUsers = new HashSet<>(); - Long mpaId = objectNode.get("mpa").get("id").asLong(); - LinkedHashSet genres = new LinkedHashSet<>(); // Используем LinkedHashSet - objectNode.get("genres").forEach(genre -> genres.add(genre.get("id").asLong())); - - return Film.builder() - .id(id) - .name(name) - .description(description) - .releaseDate(releaseDate) - .duration(duration) - .likedUsers(likedUsers) - .mpaId(mpaId) - .genres(genres) - .build(); + public List viewRaiting(@RequestParam(required = false) Long count) throws NotFoundException { + return filmInterface.viewRaiting(count); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index 7cdbea6..3ef2c45 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -4,65 +4,68 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; -import ru.yandex.practicum.filmorate.service.UserService; +import ru.yandex.practicum.filmorate.service.UserInterface; +import ru.yandex.practicum.filmorate.storage.user.UserStorage; import java.util.Collection; +import java.util.Set; @RestController @RequestMapping("/users") + public class UserController { - private final UserService userService; + private final UserStorage userStorage; + private final UserInterface userInterface; @Autowired - public UserController(UserService userService) { - this.userService = userService; + public UserController(UserStorage userStorage, UserInterface userInterface) { + this.userStorage = userStorage; + this.userInterface = userInterface; } @GetMapping public Collection findAll() { - return userService.findAll(); + return userStorage.findAll(); + } + + @GetMapping("/{id}") + public User findById(@PathVariable("id") Long id) throws ConditionsNotMetException { + return userStorage.findById(id); } @PostMapping @ResponseStatus(HttpStatus.CREATED) - public User create(@Valid @RequestBody User user) throws ValidationException, DuplicatedDataException { - return userService.create(user); + public User create(@Valid @RequestBody User user) throws ConditionsNotMetException, DuplicatedDataException { + return userStorage.create(user); } @PutMapping - public User update(@Valid @RequestBody User user) throws NotFoundException, ValidationException { - return userService.update(user); - } - - @GetMapping("/{id}") - public User getUserById(@PathVariable Long id) throws NotFoundException, ValidationException { - return userService.findById(id); + public User update(@Valid @RequestBody User newUser) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + return userStorage.update(newUser); } @PutMapping("/{id}/friends/{friendId}") - @ResponseStatus(HttpStatus.NO_CONTENT) - public void addFriend(@PathVariable Long id, @PathVariable Long friendId) throws NotFoundException { - userService.addFriend(id, friendId); + public User addFriend(@Valid @RequestBody @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + return userInterface.addFriend(id, friendId); } @DeleteMapping("/{id}/friends/{friendId}") - @ResponseStatus(HttpStatus.NO_CONTENT) - public void removeFriend(@PathVariable Long id, @PathVariable Long friendId) throws NotFoundException { - userService.removeFriend(id, friendId); + public User delFriend(@Valid @RequestBody @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + return userInterface.delFriend(id, friendId); } - @GetMapping("/{id}/friends") - public Collection getFriends(@PathVariable Long id) throws NotFoundException { - return userService.getFriends(id); + @GetMapping("/{id}/friends/common/{otherId}") + public Set findJointFriends(@Valid @RequestBody @PathVariable("id") Long id, @PathVariable("otherId") Long otherId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + return userInterface.findJointFriends(id, otherId); } - @GetMapping("/{id}/friends/common/{otherId}") - public Collection getCommonFriends(@PathVariable Long id, @PathVariable Long otherId) throws NotFoundException { - return userService.getCommonFriends(id, otherId); + @GetMapping("/{id}/friends") + public Set findJointFriends(@Valid @RequestBody @PathVariable("id") Long id) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + return userInterface.findAllFriends(id); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ConditionsNotMetException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ConditionsNotMetException.java new file mode 100644 index 0000000..d827fef --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ConditionsNotMetException.java @@ -0,0 +1,15 @@ +package ru.yandex.practicum.filmorate.exception; + +public class ConditionsNotMetException extends RuntimeException { + private String parameter; + private String reason; + + public ConditionsNotMetException(String parameter) { + this.parameter = parameter; + this.reason = reason; + } + + public Throwable fillInStackTrace() { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java index 82e3f72..9348778 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java @@ -1,7 +1,7 @@ package ru.yandex.practicum.filmorate.exception; public class NotFoundException extends RuntimeException { - public NotFoundException(String message) { + public NotFoundException(String message, String s) { super(message); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java index 4ead6ec..b6cd564 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -11,7 +11,8 @@ import lombok.EqualsAndHashCode; import java.time.LocalDate; -import java.util.*; +import java.util.LinkedHashSet; +import java.util.Set; @Data @Builder @@ -19,17 +20,29 @@ @AllArgsConstructor(staticName = "of") public class Film { private Long id; + @NotNull @NotBlank private String name; + @Description("New film update description") private String description; + @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate releaseDate; + @NotNull private Integer duration; + @JsonIgnore private Set likedUsers; - private Long mpaId; - private LinkedHashSet genres; -} \ No newline at end of file + + private Mpa mpa; // Изменено на объект Mpa + private LinkedHashSet genres; // Изменено на LinkedHashSet + + // Если вам нужно, вы можете добавить методы для получения информации о MPA + public Long getMpaId() { + return mpa != null ? mpa.getId() : null; + } +} + diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmInterface.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmInterface.java new file mode 100644 index 0000000..2ef7072 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmInterface.java @@ -0,0 +1,14 @@ +package ru.yandex.practicum.filmorate.service; + +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.FilmRequest; + +import java.util.List; + +public interface FilmInterface { + FilmRequest addLike(Long idUser, Long idFilm); + + FilmRequest delLike(Long idUser, Long idFilm); + + List viewRaiting(Long count); +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index d1ffbec..27ad4d8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -1,52 +1,184 @@ package ru.yandex.practicum.filmorate.service; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.exception.ValidationException; -import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.*; +import ru.yandex.practicum.filmorate.storage.film.FilmDbStorage; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; +import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.util.Collection; -import java.util.List; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; @Service -@Slf4j -public class FilmService { +@Slf4j(topic = "TRACE") +@ConfigurationPropertiesScan +@RequiredArgsConstructor +public class FilmService implements FilmInterface { + @Autowired + UserStorage userStorage; + @Autowired + FilmStorage filmStorage; + private final JdbcTemplate jdbcTemplate; - private final FilmStorage filmStorage; + private final String sqlQuery1 = "select filmId, userId from likedUsers"; + private final String sqlQuery2 = "insert into likedUsers(filmId, userId) " + "values (?, ?)"; + private final String sqlQuery3 = "select filmId, genreId from filmGenre where filmId = ?"; + private final String sqlQuery4 = "delete from likedUsers where filmId = ? and userId = ?"; + private final String sqlQuery5 = "select f.id as name, COUNT(l.userId) as coun from likedUsers as l LEFT OUTER JOIN film AS f ON l.filmId = f.id GROUP BY f.name ORDER BY COUNT(l.userId) DESC LIMIT 10"; + private final String sqlQuery6 = "select id, name from genre"; + private final String sqlQuery7 = "select id, name from genre where id = ?"; + private final String sqlQuery8 = "select id, rating from filmrating"; + private final String sqlQuery9 = "select id, rating from filmrating where id = ?"; - @Autowired - public FilmService(FilmStorage filmStorage) { - this.filmStorage = filmStorage; + public static class TopLikedUsersExtractor implements ResultSetExtractor> { + @Override + public LinkedHashMap extractData(ResultSet rs) throws SQLException { + LinkedHashMap data = new LinkedHashMap<>(); + while (rs.next()) { + Long filmId = rs.getLong("name"); + Long likes = rs.getLong("coun"); + data.putIfAbsent(filmId, likes); + } + return data; + } + } + + @Override + public FilmRequest addLike(Long idUser, Long idFilm) throws ConditionsNotMetException { + log.info("Обработка Post-запроса..."); + if (userStorage.findById(idUser) != null && filmStorage.findById(idFilm) != null) { + Map> likedUsers = jdbcTemplate.query(sqlQuery1, new FilmDbStorage.LikedUsersExtractor()); + if (likedUsers.get(idFilm) != null && likedUsers.get(idFilm).contains(idUser)) { + log.error("Exception", new ConditionsNotMetException(idUser.toString())); + throw new ConditionsNotMetException(idUser.toString()); + } else { + jdbcTemplate.update(sqlQuery2, idFilm, idUser); + } + } + Film film = filmStorage.findById(idFilm); + LinkedHashSet genres = new LinkedHashSet<>(); + Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmDbStorage.FilmGenreExtractor(), film.getId()); + if (!filmGenre.isEmpty()) { + for (Long g : filmGenre.get(film.getId())) + genres.add(g); + } + return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), film.getMpa(), genres); + } + + @Override + public FilmRequest delLike(Long idUser, Long idFilm) throws ConditionsNotMetException { + log.info("Обработка Del-запроса..."); + if (userStorage.findById(idUser) != null && filmStorage.findById(idFilm) != null) { + Map> likedUsers = jdbcTemplate.query(sqlQuery1, new FilmDbStorage.LikedUsersExtractor()); + if (likedUsers.get(idFilm) != null && !likedUsers.get(idFilm).contains(idUser)) { + log.error("Exception", new ConditionsNotMetException(idUser.toString())); + throw new ConditionsNotMetException(idUser.toString()); + } else jdbcTemplate.update(sqlQuery4, idFilm, idUser); + } + Film film = filmStorage.findById(idFilm); + LinkedHashSet genres = new LinkedHashSet<>(); + Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmDbStorage.FilmGenreExtractor(), film.getId()); + if (!filmGenre.isEmpty()) { + for (Long g : filmGenre.get(film.getId())) + genres.add(g); + } + return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), film.getMpa(), genres); + } + + @Override + public List viewRaiting(Long count) { + return List.of(); } - public Collection getFilms() { - return filmStorage.findAll(); + public LinkedHashSet viewRating(Long count) throws NotFoundException { + log.info("Обработка Get-запроса..."); + LinkedHashMap likedUsers = jdbcTemplate.query(sqlQuery5, new TopLikedUsersExtractor()); + LinkedHashSet films = new LinkedHashSet<>(); + if (likedUsers == null) { + log.error("Exception", new NotFoundException(count.toString(), "Список фильмов с рейтингом пуст.")); + throw new NotFoundException(count.toString(), "Список фильмов с рейтингом пуст."); + } else { + LinkedHashSet genres = new LinkedHashSet<>(); + for (Long l : likedUsers.keySet()) { + Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); + if (!filmGenre.isEmpty()) { + for (Long g : filmGenre.get(filmStorage.findById(l).getId())) + genres.add(g); + } + films.add(FilmRequest.of(filmStorage.findById(l).getId(), filmStorage.findById(l).getName(), filmStorage.findById(l).getDescription(), filmStorage.findById(l).getReleaseDate(), filmStorage.findById(l).getDuration(), new HashSet<>(), filmStorage.findById(l).getMpa(), genres)); + } + } + return films; } - public Film createFilm(Film film) throws ValidationException { - return filmStorage.create(film); + public List viewGenre() throws NotFoundException { + log.info("Обработка Get-запроса..."); + Map genre = jdbcTemplate.query(sqlQuery6, new GenreExtractor()); + List genreConstant = new ArrayList<>(); + for (Long l : genre.keySet()) + genreConstant.add(GenreConstant.of(l, genre.get(l))); + return genreConstant; } - public Film update(Film film) throws NotFoundException, ValidationException { - return filmStorage.update(film); + public static class GenreExtractor implements ResultSetExtractor> { + @Override + public Map extractData(ResultSet rs) throws SQLException { + Map data = new LinkedHashMap<>(); + while (rs.next()) { + Long id = rs.getLong("id"); + String name = rs.getString("name"); + data.put(id, name); + } + return data; + } } - public Film getFilmById(Long id) throws NotFoundException { - return filmStorage.findById(id); + public GenreConstant viewGenreName(Long id) throws NotFoundException { + log.info("Обработка Get-запроса..."); + Map genre = jdbcTemplate.query(sqlQuery7, new GenreExtractor(), id); + if (id < 0 || id > 7) { + log.error("Exception", new NotFoundException("NULL", "Жанра с указанным идентификатором не существует.")); + throw new NotFoundException("NULL", "Жанра с указанным идентификатором не существует."); + } else return GenreConstant.of(id, genre.get(id)); } - public void addLike(Long filmId, Long userId) throws NotFoundException { - filmStorage.addLike(filmId, userId); + public List viewFilmsRating() throws NotFoundException { + log.info("Обработка Get-запроса..."); + Map genre = jdbcTemplate.query(sqlQuery8, new RatingNameExtractor()); + List mpaConstant = new ArrayList<>(); + for (Long l : genre.keySet()) + mpaConstant.add(MpaConstant.of(l, genre.get(l))); + return mpaConstant; } - public void removeLike(Long filmId, Long userId) throws NotFoundException { - filmStorage.removeLike(filmId, userId); + public static class RatingNameExtractor implements ResultSetExtractor> { + @Override + public Map extractData(ResultSet rs) throws SQLException { + Map data = new HashMap<>(); + while (rs.next()) { + Long id = rs.getLong("id"); + String rating = rs.getString("rating"); + data.put(id, rating); + } + return data; + } } - public List getTopFilms(int count) { - return filmStorage.getTopFilms(count); + public MpaConstant viewRatingName(Long id) throws NotFoundException { + log.info("Обработка Get-запроса..."); + Map genre = jdbcTemplate.query(sqlQuery9, new RatingNameExtractor(), id); + if (id < 0 || id > 6) { + log.error("Exception", new NotFoundException("NULL", "Рейтинг с указанным идентификатором не существует.")); + throw new NotFoundException("NULL", "Рейтинг с указанным идентификатором не существует."); + } else return MpaConstant.of(id, genre.get(id)); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserInterface.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserInterface.java new file mode 100644 index 0000000..648199e --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserInterface.java @@ -0,0 +1,15 @@ +package ru.yandex.practicum.filmorate.service; + +import ru.yandex.practicum.filmorate.model.User; + +import java.util.Set; + +public interface UserInterface { + User addFriend(Long idUser, Long idFriend); + + User delFriend(Long idUser, Long idFriend); + + Set findJointFriends(Long idUser, Long idFriend); + + Set findAllFriends(Long idUser); +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 197a046..0f6c6d5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -1,56 +1,102 @@ package ru.yandex.practicum.filmorate.service; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; -import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; +import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.storage.user.UserDbStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; @Service -@Slf4j -public class UserService { - +@Slf4j(topic = "TRACE") +@ConfigurationPropertiesScan +@RequiredArgsConstructor +public class UserService implements UserInterface { + @Autowired + @Qualifier("UserDbStorage") private final UserStorage userStorage; + private final JdbcTemplate jdbcTemplate; - @Autowired - public UserService(UserStorage userStorage) { - this.userStorage = userStorage; - } + @Override + public User addFriend(Long idUser, Long idFriend) throws ConditionsNotMetException { + log.info("Обработка Post-запроса..."); + String sqlQuery2 = "select userId, friendId from friends"; + Map> friends = jdbcTemplate.query(sqlQuery2, new UserDbStorage.FriendsExtractor()); - public Collection findAll() { - return userStorage.findAll(); + if (friends.get(idUser) != null && friends.get(idUser).contains(idFriend)) { + log.error("Exception", new ConditionsNotMetException("Пользователь с ID " + idFriend + " уже добавлен в друзья")); + throw new ConditionsNotMetException("Пользователь с ID " + idFriend + " уже добавлен в друзья"); + } + if (userStorage.findById(idFriend) == null) { + log.error("Exception", new NotFoundException("Пользователь с ID " + idFriend + " отсутствует в базе", "Список фильмов с рейтингом пуст.")); + throw new NotFoundException("Пользователь с ID " + idFriend + " отсутствует в базе", "Список фильмов с рейтингом пуст."); + } + String sqlQuery = "insert into friends(userId, friendId) values (?, ?)"; + jdbcTemplate.update(sqlQuery, idUser, idFriend); + return userStorage.findById(idUser); } - public User create(User user) throws ValidationException, DuplicatedDataException { - return userStorage.create(user); - } + @Override + public User delFriend(Long idUser, Long idFriend) throws ConditionsNotMetException { + log.info("Обработка Del-запроса..."); + String sqlQuery = "delete from friends where userId = ? and friendId = ?"; + jdbcTemplate.update(sqlQuery, idUser, idFriend); - public User update(User user) throws NotFoundException, ValidationException { - return userStorage.update(user); + if (userStorage.findById(idUser) == null) { + log.error("Exception", new NotFoundException("Пользователь с ID " + idUser + " отсутствует в базе", "Список фильмов с рейтингом пуст.")); + throw new NotFoundException("Пользователь с ID " + idUser + " отсутствует в базе", "Список фильмов с рейтингом пуст."); + } + if (userStorage.findById(idFriend) == null) { + log.error("Exception", new NotFoundException("Пользователь с ID " + idFriend + " отсутствует в базе", "Список фильмов с рейтингом пуст.")); + throw new NotFoundException("Пользователь с ID " + idFriend + " отсутствует в базе", "Список фильмов с рейтингом пуст."); + } + return userStorage.findById(idUser); } - public User findById(Long id) throws NotFoundException, ValidationException { - return userStorage.findById(id); - } + @Override + public Set findJointFriends(Long idUser, Long idFriend) throws NotFoundException { + log.info("Обработка Get-запроса..."); + String sqlQuery2 = "select userId, friendId from friends"; + Map> friends = jdbcTemplate.query(sqlQuery2, new UserDbStorage.FriendsExtractor()); + Set result = new HashSet<>(friends.get(idUser)); + result.retainAll(friends.get(idFriend)); - public void addFriend(Long userId, Long friendId) throws NotFoundException { - userStorage.addFriend(userId, friendId); + Set set = new HashSet<>(); + for (Long f : result) { + set.add(userStorage.findById(f)); + } + return set; } - public void removeFriend(Long userId, Long friendId) throws NotFoundException { - userStorage.removeFriend(userId, friendId); - } + @Override + public Set findAllFriends(Long idUser) throws NotFoundException { + log.info("Обработка Get-запроса..."); + String sqlQuery2 = "select userId, friendId from friends"; + Map> friends = jdbcTemplate.query(sqlQuery2, new UserDbStorage.FriendsExtractor()); - public Collection getFriends(Long id) throws NotFoundException { - return userStorage.getFriends(id); - } + if (userStorage.findById(idUser) == null) { + log.error("Exception", new NotFoundException("Пользователь с ID " + idUser + " отсутствует в базе", "Список фильмов с рейтингом пуст.")); + throw new NotFoundException("Пользователь с ID " + idUser + " отсутствует в базе", "Список фильмов с рейтингом пуст."); + } - public Collection getCommonFriends(Long userId, Long otherUserId) throws NotFoundException { - return userStorage.getCommonFriends(userId, otherUserId); + if (friends.get(idUser) == null) { + return new HashSet<>(); + } else { + Set set = new HashSet<>(); + for (Long f : friends.get(idUser)) { + set.add(userStorage.findById(f)); + } + return set; + } } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index a3aeb9d..d97550a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; import org.springframework.stereotype.Component; @@ -13,6 +14,8 @@ import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.storage.user.UserStorage; +import java.sql.ResultSet; +import java.sql.SQLException; import java.time.LocalDate; import java.util.*; @@ -57,7 +60,7 @@ public Film findById(Long id) throws NotFoundException { try { return jdbcTemplate.queryForObject(FIND_FILM_BY_ID, FILM_ROW_MAPPER, id); } catch (DataAccessException e) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, id)); + throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, id), "Список фильмов с рейтингом пуст."); } } @@ -86,7 +89,7 @@ public Film update(Film film) throws NotFoundException, ValidationException { validateFilm(film); if (!existsById(film.getId())) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, film.getId())); + throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, film.getId()), "Список фильмов с рейтингом пуст."); } int rowsAffected = jdbcTemplate.update(UPDATE_FILM, @@ -97,7 +100,7 @@ public Film update(Film film) throws NotFoundException, ValidationException { film.getId()); if (rowsAffected == 0) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, film.getId())); + throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, film.getId()), "Список фильмов с рейтингом пуст."); } log.info("Film with ID = {} updated: {}", film.getId(), film); @@ -107,10 +110,10 @@ public Film update(Film film) throws NotFoundException, ValidationException { @Override public void addLike(Long filmId, Long userId) throws NotFoundException { if (!existsById(filmId)) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId)); + throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId), "Список фильмов с рейтингом пуст."); } if (userStorage.findById(userId) == null) { - throw new NotFoundException(String.format("User with ID = %d not found", userId)); + throw new NotFoundException(String.format("User with ID = %d not found", userId), "Список фильмов с рейтингом пуст."); } jdbcTemplate.update(ADD_LIKE, filmId, userId); @@ -120,15 +123,15 @@ public void addLike(Long filmId, Long userId) throws NotFoundException { @Override public void removeLike(Long filmId, Long userId) throws NotFoundException { if (!existsById(filmId)) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId)); + throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId), "Список фильмов с рейтингом пуст."); } if (userStorage.findById(userId) == null) { - throw new NotFoundException(String.format("User with ID = %d not found", userId)); + throw new NotFoundException(String.format("User with ID = %d not found", userId), "Список фильмов с рейтингом пуст."); } int rowsAffected = jdbcTemplate.update(REMOVE_LIKE, filmId, userId); if (rowsAffected == 0) { - throw new NotFoundException(String.format("User with ID = %d did not like the film with ID = %d", userId, filmId)); + throw new NotFoundException(String.format("User with ID = %d did not like the film with ID = %d", userId, filmId), "Список фильмов с рейтингом пуст."); } log.info("User with ID = {} unliked the film with ID = {}", userId, filmId); @@ -158,4 +161,32 @@ private void validateFilm(Film film) throws ValidationException { throw new ValidationException(ExceptionMessages.FILM_DURATION_INVALID); } } + + public static class LikedUsersExtractor implements ResultSetExtractor>> { + @Override + public Map> extractData(ResultSet rs) throws SQLException { + Map> likedUsers = new HashMap<>(); + while (rs.next()) { + Long filmId = rs.getLong("filmId"); + Long userId = rs.getLong("userId"); + + likedUsers.computeIfAbsent(filmId, k -> new HashSet<>()).add(userId); + } + return likedUsers; + } + } + + public static class FilmGenreExtractor implements ResultSetExtractor>> { + @Override + public Map> extractData(ResultSet rs) throws SQLException { + Map> filmGenre = new HashMap<>(); + while (rs.next()) { + Long filmId = rs.getLong("filmId"); + Long genreId = rs.getLong("genreId"); + + filmGenre.computeIfAbsent(filmId, k -> new LinkedHashSet<>()).add(genreId); + } + return filmGenre; + } + } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java index 5762564..bec462c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java @@ -15,10 +15,4 @@ public interface FilmStorage { Film create(Film film); Film update(Film film) throws NotFoundException; - - void addLike(Long filmId, Long userId) throws NotFoundException; - - void removeLike(Long filmId, Long userId) throws NotFoundException; - - List getTopFilms(int count); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 8319e95..d16375a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -2,8 +2,10 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; import org.springframework.stereotype.Component; @@ -12,7 +14,8 @@ import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; - +import java.sql.ResultSet; +import java.sql.SQLException; import java.time.LocalDate; import java.util.*; import java.util.stream.Collectors; @@ -20,6 +23,7 @@ @Component @RequiredArgsConstructor @Slf4j +@Qualifier("UserDbStorage") public class UserDbStorage implements UserStorage { private final JdbcTemplate jdbcTemplate; @@ -87,7 +91,7 @@ public User update(User newUser) throws NotFoundException, ValidationException { throw new ValidationException("User ID cannot be null"); } if (!existsById(newUser.getId())) { - throw new NotFoundException("User with ID = " + newUser.getId() + " not found"); + throw new NotFoundException("User with ID = " + newUser.getId() + " not found", "Список фильмов с рейтингом пуст."); } validateEmail(newUser.getEmail()); @@ -103,7 +107,7 @@ public User update(User newUser) throws NotFoundException, ValidationException { newUser.getId()); if (rowsAffected == 0) { - throw new NotFoundException("User with ID = " + newUser.getId() + " not found"); + throw new NotFoundException("User with ID = " + newUser.getId() + " not found", "Список фильмов с рейтингом пуст."); } log.info("User with ID = {} updated: {}", newUser.getId(), newUser); @@ -118,17 +122,17 @@ public User findById(Long id) throws NotFoundException { try { return jdbcTemplate.queryForObject(FIND_USER_BY_ID, USER_ROW_MAPPER, id); } catch (DataAccessException e) { - throw new NotFoundException("User with ID = " + id + " not found"); + throw new NotFoundException("User with ID = " + id + " not found", "Список фильмов с рейтингом пуст."); } } @Override public void addFriend(Long userId, Long friendId) throws NotFoundException { if (!existsById(userId)) { - throw new NotFoundException("User with ID = " + userId + " not found"); + throw new NotFoundException("User with ID = " + userId + " not found", "Список фильмов с рейтингом пуст."); } if (!existsById(friendId)) { - throw new NotFoundException("User with ID = " + friendId + " not found"); + throw new NotFoundException("User with ID = " + friendId + " not found", "Список фильмов с рейтингом пуст."); } // Добавление друга @@ -139,10 +143,10 @@ public void addFriend(Long userId, Long friendId) throws NotFoundException { @Override public User removeFriend(Long userId, Long friendId) throws NotFoundException { if (!existsById(userId)) { - throw new NotFoundException("User with ID = " + userId + " not found"); + throw new NotFoundException("User with ID = " + userId + " not found", "Список фильмов с рейтингом пуст."); } if (!existsById(friendId)) { - throw new NotFoundException("User with ID = " + friendId + " not found"); + throw new NotFoundException("User with ID = " + friendId + " not found", "Список фильмов с рейтингом пуст."); } // Удаление друга @@ -154,7 +158,7 @@ public User removeFriend(Long userId, Long friendId) throws NotFoundException { @Override public Collection getFriends(Long id) throws NotFoundException { if (!existsById(id)) { - throw new NotFoundException("User with ID = " + id + " not found"); + throw new NotFoundException("User with ID = " + id + " not found", "Список фильмов с рейтингом пуст."); } return jdbcTemplate.query(GET_FRIENDS, USER_ROW_MAPPER, id); @@ -163,10 +167,10 @@ public Collection getFriends(Long id) throws NotFoundException { @Override public Collection getCommonFriends(Long userId, Long otherUserId) throws NotFoundException { if (!existsById(userId)) { - throw new NotFoundException("User with ID = " + userId + " not found"); + throw new NotFoundException("User with ID = " + userId + " not found", "Список фильмов с рейтингом пуст."); } if (!existsById(otherUserId)) { - throw new NotFoundException("User with ID = " + otherUserId + " not found"); + throw new NotFoundException("User with ID = " + otherUserId + " not found", "Список фильмов с рейтингом пуст."); } // Получение общих друзей @@ -185,7 +189,7 @@ private boolean existsById(Long id) { } private Set getFriendIds(Long userId) { - return jdbcTemplate.queryForList("SELECT friend_id FROM friends WHERE user_id = ?", Long.class, userId) + return jdbcTemplate.queryForList("SELECT friendId FROM friends WHERE userId = ?", Long.class, userId) .stream() .collect(Collectors.toSet()); } @@ -210,4 +214,18 @@ private void validateBirthday(LocalDate birthday) throws ValidationException { throw new ValidationException("Birthday cannot be in the future"); } } + + public static class FriendsExtractor implements ResultSetExtractor>> { + @Override + public Map> extractData(ResultSet rs) throws SQLException { + Map> friends = new HashMap<>(); + while (rs.next()) { + Long userId = rs.getLong("userId"); + Long friendId = rs.getLong("friendId"); + + friends.computeIfAbsent(userId, k -> new HashSet<>()).add(friendId); + } + return friends; + } + } } \ No newline at end of file From 883df5189d4bf19b23aabf4cf40de451f5714616 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 03:10:01 +0500 Subject: [PATCH 008/118] =?UTF-8?q?=D0=BE=D0=BF=D1=8F=D1=82=D1=8C=20=D1=81?= =?UTF-8?q?=D1=82=D0=B8=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/storage/film/FilmStorage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java index bec462c..2241ba3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java @@ -4,7 +4,6 @@ import ru.yandex.practicum.filmorate.model.Film; import java.util.Collection; -import java.util.List; public interface FilmStorage { From a1292fba21197ded0acda8b68eed3a31eb1eba73 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 03:13:30 +0500 Subject: [PATCH 009/118] =?UTF-8?q?=D0=BF=D0=BE=D1=84=D0=B8=D0=BA=D1=81?= =?UTF-8?q?=D0=B8=D0=BB=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D1=87=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/film/FilmDbStorage.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index d97550a..3940834 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -107,7 +107,6 @@ public Film update(Film film) throws NotFoundException, ValidationException { return findById(film.getId()); } - @Override public void addLike(Long filmId, Long userId) throws NotFoundException { if (!existsById(filmId)) { throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId), "Список фильмов с рейтингом пуст."); @@ -120,7 +119,6 @@ public void addLike(Long filmId, Long userId) throws NotFoundException { log.info("User with ID = {} liked the film with ID = {}", userId, filmId); } - @Override public void removeLike(Long filmId, Long userId) throws NotFoundException { if (!existsById(filmId)) { throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId), "Список фильмов с рейтингом пуст."); @@ -137,7 +135,6 @@ public void removeLike(Long filmId, Long userId) throws NotFoundException { log.info("User with ID = {} unliked the film with ID = {}", userId, filmId); } - @Override public List getTopFilms(int count) { log.info("Getting top-{} films by number of likes", count); return jdbcTemplate.query(GET_TOP_FILMS, FILM_ROW_MAPPER, count); From b6d1eb9ea9712dfc418159b1cbbed84372ed58e5 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 03:33:54 +0500 Subject: [PATCH 010/118] =?UTF-8?q?3=20=D1=83=D1=82=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/UserController.java | 12 +++--- .../exception/ConditionsNotMetException.java | 13 +++--- .../filmorate/service/FilmService.java | 1 - .../filmorate/service/UserService.java | 41 ++++++++----------- 4 files changed, 31 insertions(+), 36 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index 3ef2c45..d000423 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -2,6 +2,7 @@ import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; @@ -18,7 +19,8 @@ @RequestMapping("/users") public class UserController { - + @Autowired + @Qualifier("UserDbStorage") private final UserStorage userStorage; private final UserInterface userInterface; @@ -50,22 +52,22 @@ public User update(@Valid @RequestBody User newUser) throws ConditionsNotMetExce } @PutMapping("/{id}/friends/{friendId}") - public User addFriend(@Valid @RequestBody @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + public User addFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { return userInterface.addFriend(id, friendId); } @DeleteMapping("/{id}/friends/{friendId}") - public User delFriend(@Valid @RequestBody @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + public User delFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { return userInterface.delFriend(id, friendId); } @GetMapping("/{id}/friends/common/{otherId}") - public Set findJointFriends(@Valid @RequestBody @PathVariable("id") Long id, @PathVariable("otherId") Long otherId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + public Set findJointFriends(@Valid @PathVariable("id") Long id, @PathVariable("otherId") Long otherId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { return userInterface.findJointFriends(id, otherId); } @GetMapping("/{id}/friends") - public Set findJointFriends(@Valid @RequestBody @PathVariable("id") Long id) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + public Set findJointFriends(@Valid @PathVariable("id") Long id) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { return userInterface.findAllFriends(id); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ConditionsNotMetException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ConditionsNotMetException.java index d827fef..8972e35 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/ConditionsNotMetException.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ConditionsNotMetException.java @@ -1,15 +1,14 @@ package ru.yandex.practicum.filmorate.exception; public class ConditionsNotMetException extends RuntimeException { - private String parameter; - private String reason; - public ConditionsNotMetException(String parameter) { - this.parameter = parameter; - this.reason = reason; + private final String id; // Идентификатор, связанный с ошибкой + + public ConditionsNotMetException(String id) { + this.id = id; } - public Throwable fillInStackTrace() { - return null; + public String getId() { + return id; } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 27ad4d8..e066a74 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -94,7 +94,6 @@ public FilmRequest delLike(Long idUser, Long idFilm) throws ConditionsNotMetExce return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), film.getMpa(), genres); } - @Override public List viewRaiting(Long count) { return List.of(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 0f6c6d5..e80631f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -24,9 +24,10 @@ public class UserService implements UserInterface { @Autowired @Qualifier("UserDbStorage") - private final UserStorage userStorage; + UserStorage userStorage; private final JdbcTemplate jdbcTemplate; + @Override public User addFriend(Long idUser, Long idFriend) throws ConditionsNotMetException { log.info("Обработка Post-запроса..."); @@ -34,16 +35,17 @@ public User addFriend(Long idUser, Long idFriend) throws ConditionsNotMetExcepti Map> friends = jdbcTemplate.query(sqlQuery2, new UserDbStorage.FriendsExtractor()); if (friends.get(idUser) != null && friends.get(idUser).contains(idFriend)) { - log.error("Exception", new ConditionsNotMetException("Пользователь с ID " + idFriend + " уже добавлен в друзья")); - throw new ConditionsNotMetException("Пользователь с ID " + idFriend + " уже добавлен в друзья"); + log.error("Exception", new ConditionsNotMetException(idFriend.toString())); + throw new ConditionsNotMetException(idFriend.toString()); } if (userStorage.findById(idFriend) == null) { - log.error("Exception", new NotFoundException("Пользователь с ID " + idFriend + " отсутствует в базе", "Список фильмов с рейтингом пуст.")); - throw new NotFoundException("Пользователь с ID " + idFriend + " отсутствует в базе", "Список фильмов с рейтингом пуст."); + log.error("Exception", new NotFoundException(idFriend.toString(), "Пользователь с данным идентификатором отсутствует в базе")); + throw new NotFoundException(idFriend.toString(), "Пользователь с данным идентификатором отсутствует в базе"); } - String sqlQuery = "insert into friends(userId, friendId) values (?, ?)"; + String sqlQuery = "insert into friends(userId, friendId) " + "values (?, ?)"; jdbcTemplate.update(sqlQuery, idUser, idFriend); return userStorage.findById(idUser); + } @Override @@ -51,14 +53,13 @@ public User delFriend(Long idUser, Long idFriend) throws ConditionsNotMetExcepti log.info("Обработка Del-запроса..."); String sqlQuery = "delete from friends where userId = ? and friendId = ?"; jdbcTemplate.update(sqlQuery, idUser, idFriend); - if (userStorage.findById(idUser) == null) { - log.error("Exception", new NotFoundException("Пользователь с ID " + idUser + " отсутствует в базе", "Список фильмов с рейтингом пуст.")); - throw new NotFoundException("Пользователь с ID " + idUser + " отсутствует в базе", "Список фильмов с рейтингом пуст."); + log.error("Exception", new NotFoundException(idUser.toString(), "Пользователь с данным идентификатором отсутствует в базе")); + throw new NotFoundException(idUser.toString(), "Пользователь с данным идентификатором отсутствует в базе"); } if (userStorage.findById(idFriend) == null) { - log.error("Exception", new NotFoundException("Пользователь с ID " + idFriend + " отсутствует в базе", "Список фильмов с рейтингом пуст.")); - throw new NotFoundException("Пользователь с ID " + idFriend + " отсутствует в базе", "Список фильмов с рейтингом пуст."); + log.error("Exception", new NotFoundException(idUser.toString(), "Пользователь с данным идентификатором отсутствует в базе")); + throw new NotFoundException(idUser.toString(), "Пользователь с данным идентификатором отсутствует в базе"); } return userStorage.findById(idUser); } @@ -70,11 +71,9 @@ public Set findJointFriends(Long idUser, Long idFriend) throws NotFoundExc Map> friends = jdbcTemplate.query(sqlQuery2, new UserDbStorage.FriendsExtractor()); Set result = new HashSet<>(friends.get(idUser)); result.retainAll(friends.get(idFriend)); - Set set = new HashSet<>(); - for (Long f : result) { + for (Long f : result) set.add(userStorage.findById(f)); - } return set; } @@ -83,19 +82,15 @@ public Set findAllFriends(Long idUser) throws NotFoundException { log.info("Обработка Get-запроса..."); String sqlQuery2 = "select userId, friendId from friends"; Map> friends = jdbcTemplate.query(sqlQuery2, new UserDbStorage.FriendsExtractor()); - if (userStorage.findById(idUser) == null) { - log.error("Exception", new NotFoundException("Пользователь с ID " + idUser + " отсутствует в базе", "Список фильмов с рейтингом пуст.")); - throw new NotFoundException("Пользователь с ID " + idUser + " отсутствует в базе", "Список фильмов с рейтингом пуст."); + log.error("Exception", new NotFoundException(idUser.toString(), "Пользователь с данным идентификатором отсутствует в базе")); + throw new NotFoundException(idUser.toString(), "Пользователь с данным идентификатором отсутствует в базе"); } - - if (friends.get(idUser) == null) { - return new HashSet<>(); - } else { + if (friends.get(idUser) == null) return new HashSet<>(); + else { Set set = new HashSet<>(); - for (Long f : friends.get(idUser)) { + for (Long f : friends.get(idUser)) set.add(userStorage.findById(f)); - } return set; } } From f9f1c7796366bcbf434f2be6a98d5e2fd8ad7f28 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 10:47:22 +0500 Subject: [PATCH 011/118] =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=D0=B0=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20=D1=84?= =?UTF-8?q?=D0=B8=D0=BB=D1=8C=D0=BC=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 119 +++++++++++++----- 1 file changed, 88 insertions(+), 31 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 3940834..7082f93 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -12,11 +12,14 @@ import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.Genre; +import ru.yandex.practicum.filmorate.model.Mpa; import ru.yandex.practicum.filmorate.storage.user.UserStorage; import java.sql.ResultSet; import java.sql.SQLException; import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.*; @Component @@ -24,32 +27,44 @@ @Slf4j public class FilmDbStorage implements FilmStorage { + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private final JdbcTemplate jdbcTemplate; private final UserStorage userStorage; // SQL-запросы - private static final String FIND_ALL_FILMS = "SELECT * FROM films"; - private static final String FIND_FILM_BY_ID = "SELECT * FROM films WHERE id = ?"; - private static final String INSERT_FILM = "INSERT INTO films (name, description, release_date, duration) VALUES (?, ?, ?, ?)"; - private static final String UPDATE_FILM = "UPDATE films SET name = ?, description = ?, release_date = ?, duration = ? WHERE id = ?"; - private static final String ADD_LIKE = "INSERT INTO likes (filmID, userID) VALUES (?, ?)"; - private static final String REMOVE_LIKE = "DELETE FROM likes WHERE filmID = ? AND userID = ?"; - private static final String GET_TOP_FILMS = "SELECT f.* FROM films f LEFT JOIN likes l ON f.id = l.filmID GROUP BY f.id ORDER BY COUNT(l.userID) DESC LIMIT ?"; - - // Метод для отображения строки из результата запроса в объект Film + private final String sqlQuery1 = "select id, name, description, releaseDate, duration from film"; + private final String sqlQuery2 = "select filmId, userId from likedUsers"; + private final String sqlQuery3 = "select filmId, genreId from filmGenre"; + private final String sqlQuery4 = "select id, ratingId from film"; + private final String sqlQuery5 = "select id, name, description, releaseDate, duration from film where id = ?"; + private final String sqlQuery6 = "select filmId, userId from likedUsers where filmId = ?"; + private final String sqlQuery7 = "select filmId, genreId from filmGenre where filmId = ?"; + private final String sqlQuery8 = "select id, ratingId from film where id = ?"; + private final String sqlQuery9 = "select id, name from genre"; + private final String sqlQuery10 = "select id, rating from filmrating"; + private final String sqlQuery11 = "delete from filmGenre where filmId = ?"; + private final String sqlQuery12 = "insert into filmGenre(filmId, genreId) values (?, ?)"; + private final String sqlQuery13 = "update film set name = ?, description = ?, releaseDate = ?, duration = ?, ratingId = ? where id = ?"; + private final String sqlQuery14 = "update film set ratingId = ? where id = ?"; + + // Маппер для преобразования строки ResultSet в объект Film private static final RowMapper FILM_ROW_MAPPER = (rs, rowNum) -> Film.builder() .id(rs.getLong("id")) .name(rs.getString("name")) .description(rs.getString("description")) - .releaseDate(rs.getDate("release_date").toLocalDate()) + .releaseDate(rs.getDate("releaseDate").toLocalDate()) .duration(rs.getInt("duration")) .likedUsers(new HashSet<>()) // Лайки будут загружаться отдельно + .mpa(Mpa.of(rs.getLong("ratingId"), null)) // Используем статический метод of + .genres(new LinkedHashSet<>()) // Жанры будут загружены отдельно .build(); @Override public Collection findAll() { log.info("Processing Get-request..."); - return jdbcTemplate.query(FIND_ALL_FILMS, FILM_ROW_MAPPER); + List films = jdbcTemplate.query(sqlQuery1, FILM_ROW_MAPPER); + films.forEach(this::loadAdditionalData); // Загружаем дополнительные данные (лайки, жанры, MPA) + return films; } @Override @@ -58,7 +73,11 @@ public Film findById(Long id) throws NotFoundException { throw new ValidationException(ExceptionMessages.FILM_ID_CANNOT_BE_NULL); } try { - return jdbcTemplate.queryForObject(FIND_FILM_BY_ID, FILM_ROW_MAPPER, id); + Film film = jdbcTemplate.queryForObject(sqlQuery5, FILM_ROW_MAPPER, id); + if (film != null) { + loadAdditionalData(film); // Загружаем дополнительные данные (лайки, жанры, MPA) + } + return film; } catch (DataAccessException e) { throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, id), "Список фильмов с рейтингом пуст."); } @@ -69,17 +88,26 @@ public Film create(Film film) throws ValidationException { validateFilm(film); SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate) - .withTableName("films") + .withTableName("film") .usingGeneratedKeyColumns("id"); Map parameters = Map.of( "name", film.getName(), "description", film.getDescription(), - "release_date", film.getReleaseDate(), - "duration", film.getDuration() + "releaseDate", film.getReleaseDate(), + "duration", film.getDuration(), + "ratingId", film.getMpa().getId() ); long filmId = insert.executeAndReturnKey(parameters).longValue(); film.setId(filmId); + // Сохраняем жанры + if (film.getGenres() != null && !film.getGenres().isEmpty()) { + jdbcTemplate.update(sqlQuery11, filmId); // Удаляем старые жанры + for (Genre genre : film.getGenres()) { + jdbcTemplate.update(sqlQuery12, filmId, genre.getId()); // Вставляем новые жанры + } + } + log.info("Film created: {}", film); return findById(filmId); } @@ -92,15 +120,20 @@ public Film update(Film film) throws NotFoundException, ValidationException { throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, film.getId()), "Список фильмов с рейтингом пуст."); } - int rowsAffected = jdbcTemplate.update(UPDATE_FILM, + jdbcTemplate.update(sqlQuery13, film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), + film.getMpa().getId(), film.getId()); - if (rowsAffected == 0) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, film.getId()), "Список фильмов с рейтингом пуст."); + // Обновляем жанры + if (film.getGenres() != null) { + jdbcTemplate.update(sqlQuery11, film.getId()); // Удаляем старые жанры + for (Genre genre : film.getGenres()) { + jdbcTemplate.update(sqlQuery12, film.getId(), genre.getId()); // Вставляем новые жанры + } } log.info("Film with ID = {} updated: {}", film.getId(), film); @@ -115,7 +148,7 @@ public void addLike(Long filmId, Long userId) throws NotFoundException { throw new NotFoundException(String.format("User with ID = %d not found", userId), "Список фильмов с рейтингом пуст."); } - jdbcTemplate.update(ADD_LIKE, filmId, userId); + jdbcTemplate.update("INSERT INTO likedUsers (filmId, userId) VALUES (?, ?)", filmId, userId); log.info("User with ID = {} liked the film with ID = {}", userId, filmId); } @@ -127,21 +160,20 @@ public void removeLike(Long filmId, Long userId) throws NotFoundException { throw new NotFoundException(String.format("User with ID = %d not found", userId), "Список фильмов с рейтингом пуст."); } - int rowsAffected = jdbcTemplate.update(REMOVE_LIKE, filmId, userId); - if (rowsAffected == 0) { - throw new NotFoundException(String.format("User with ID = %d did not like the film with ID = %d", userId, filmId), "Список фильмов с рейтингом пуст."); - } - + jdbcTemplate.update("DELETE FROM likedUsers WHERE filmId = ? AND userId = ?", filmId, userId); log.info("User with ID = {} unliked the film with ID = {}", userId, filmId); } public List getTopFilms(int count) { log.info("Getting top-{} films by number of likes", count); - return jdbcTemplate.query(GET_TOP_FILMS, FILM_ROW_MAPPER, count); + String sql = "SELECT f.* FROM film f LEFT JOIN likedUsers l ON f.id = l.filmId GROUP BY f.id ORDER BY COUNT(l.userId) DESC LIMIT ?"; + List films = jdbcTemplate.query(sql, FILM_ROW_MAPPER, count); + films.forEach(this::loadAdditionalData); // Загружаем дополнительные данные (лайки, жанры, MPA) + return films; } private boolean existsById(Long id) { - return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM films WHERE id = ?", Integer.class, id) > 0; + return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM film WHERE id = ?", Integer.class, id) > 0; } private void validateFilm(Film film) throws ValidationException { @@ -159,6 +191,32 @@ private void validateFilm(Film film) throws ValidationException { } } + // Метод для загрузки дополнительных данных (лайки, жанры, MPA) + private void loadAdditionalData(Film film) { + Long filmId = film.getId(); + + // Загружаем лайки + Map> likedUsers = jdbcTemplate.query(sqlQuery6, new LikedUsersExtractor(), filmId); + film.setLikedUsers(likedUsers.getOrDefault(filmId, new HashSet<>())); + + // Загружаем жанры + Map> filmGenres = jdbcTemplate.query(sqlQuery7, new FilmGenreExtractor(), filmId); + LinkedHashSet genres = new LinkedHashSet<>(); + if (filmGenres.containsKey(filmId)) { + for (Long genreId : filmGenres.get(filmId)) { + // Используем статический метод of для создания объекта Genre + genres.add(Genre.of(genreId, null)); // Название жанра будет загружено отдельно + } + } + film.setGenres(genres); + + // Загружаем MPA + Long ratingId = jdbcTemplate.queryForObject(sqlQuery8, Long.class, filmId); + String ratingName = jdbcTemplate.queryForObject("SELECT rating FROM filmrating WHERE id = ?", String.class, ratingId); + film.setMpa(Mpa.of(ratingId, ratingName)); // Используем статический метод of + } + + // Extractor для лайков public static class LikedUsersExtractor implements ResultSetExtractor>> { @Override public Map> extractData(ResultSet rs) throws SQLException { @@ -166,24 +224,23 @@ public Map> extractData(ResultSet rs) throws SQLException { while (rs.next()) { Long filmId = rs.getLong("filmId"); Long userId = rs.getLong("userId"); - likedUsers.computeIfAbsent(filmId, k -> new HashSet<>()).add(userId); } return likedUsers; } } + // Extractor для жанров public static class FilmGenreExtractor implements ResultSetExtractor>> { @Override public Map> extractData(ResultSet rs) throws SQLException { - Map> filmGenre = new HashMap<>(); + Map> filmGenres = new HashMap<>(); while (rs.next()) { Long filmId = rs.getLong("filmId"); Long genreId = rs.getLong("genreId"); - - filmGenre.computeIfAbsent(filmId, k -> new LinkedHashSet<>()).add(genreId); + filmGenres.computeIfAbsent(filmId, k -> new LinkedHashSet<>()).add(genreId); } - return filmGenre; + return filmGenres; } } } \ No newline at end of file From a4677094073919c6057be11d6ead0cab8f05a314 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 11:08:55 +0500 Subject: [PATCH 012/118] 14 --- .../filmorate/controller/FilmController.java | 2 +- .../practicum/filmorate/model/Film.java | 21 +- .../filmorate/service/FilmService.java | 4 +- .../filmorate/storage/film/FilmDbStorage.java | 386 ++++++++++-------- .../filmorate/storage/film/FilmStorage.java | 3 +- 5 files changed, 216 insertions(+), 200 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 5410a92..f8cfd35 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -37,7 +37,7 @@ public Collection findAll() { } @GetMapping("/{id}") - public Film findById(@PathVariable("id") Long id) throws ConditionsNotMetException, NotFoundException { + public FilmRequest findById(@PathVariable("id") Long id) throws ConditionsNotMetException, NotFoundException { return filmStorage.findById(id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java index b6cd564..034e5de 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -11,8 +11,7 @@ import lombok.EqualsAndHashCode; import java.time.LocalDate; -import java.util.LinkedHashSet; -import java.util.Set; +import java.util.*; @Data @Builder @@ -20,29 +19,17 @@ @AllArgsConstructor(staticName = "of") public class Film { private Long id; - @NotNull @NotBlank private String name; - @Description("New film update description") private String description; - @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate releaseDate; - @NotNull private Integer duration; - @JsonIgnore private Set likedUsers; - - private Mpa mpa; // Изменено на объект Mpa - private LinkedHashSet genres; // Изменено на LinkedHashSet - - // Если вам нужно, вы можете добавить методы для получения информации о MPA - public Long getMpaId() { - return mpa != null ? mpa.getId() : null; - } -} - + private Long mpa; + private LinkedHashSet genres; +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index e066a74..bbd1b9f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -64,7 +64,7 @@ public FilmRequest addLike(Long idUser, Long idFilm) throws ConditionsNotMetExce jdbcTemplate.update(sqlQuery2, idFilm, idUser); } } - Film film = filmStorage.findById(idFilm); + FilmRequest film = filmStorage.findById(idFilm); LinkedHashSet genres = new LinkedHashSet<>(); Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmDbStorage.FilmGenreExtractor(), film.getId()); if (!filmGenre.isEmpty()) { @@ -84,7 +84,7 @@ public FilmRequest delLike(Long idUser, Long idFilm) throws ConditionsNotMetExce throw new ConditionsNotMetException(idUser.toString()); } else jdbcTemplate.update(sqlQuery4, idFilm, idUser); } - Film film = filmStorage.findById(idFilm); + FilmRequest film = filmStorage.findById(idFilm); LinkedHashSet genres = new LinkedHashSet<>(); Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmDbStorage.FilmGenreExtractor(), film.getId()); if (!filmGenre.isEmpty()) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 7082f93..c48ed46 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -1,37 +1,42 @@ package ru.yandex.practicum.filmorate.storage.film; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; -import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; import org.springframework.stereotype.Component; -import ru.yandex.practicum.filmorate.exception.ExceptionMessages; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.exception.ValidationException; -import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.model.Genre; -import ru.yandex.practicum.filmorate.model.Mpa; -import ru.yandex.practicum.filmorate.storage.user.UserStorage; +import ru.yandex.practicum.filmorate.model.*; +import ru.yandex.practicum.filmorate.service.FilmInterface; +import ru.yandex.practicum.filmorate.service.FilmService; import java.sql.ResultSet; import java.sql.SQLException; -import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.chrono.ChronoLocalDate; import java.time.format.DateTimeFormatter; import java.util.*; +import java.util.stream.Collectors; -@Component +@Repository @RequiredArgsConstructor -@Slf4j +@Slf4j(topic = "TRACE") +@ConfigurationPropertiesScan +@Component +@Qualifier("FilmDbStorage") public class FilmDbStorage implements FilmStorage { private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private final JdbcTemplate jdbcTemplate; - private final UserStorage userStorage; + private FilmInterface filmInterface; - // SQL-запросы private final String sqlQuery1 = "select id, name, description, releaseDate, duration from film"; private final String sqlQuery2 = "select filmId, userId from likedUsers"; private final String sqlQuery3 = "select filmId, genreId from filmGenre"; @@ -43,204 +48,227 @@ public class FilmDbStorage implements FilmStorage { private final String sqlQuery9 = "select id, name from genre"; private final String sqlQuery10 = "select id, rating from filmrating"; private final String sqlQuery11 = "delete from filmGenre where filmId = ?"; - private final String sqlQuery12 = "insert into filmGenre(filmId, genreId) values (?, ?)"; - private final String sqlQuery13 = "update film set name = ?, description = ?, releaseDate = ?, duration = ?, ratingId = ? where id = ?"; - private final String sqlQuery14 = "update film set ratingId = ? where id = ?"; - - // Маппер для преобразования строки ResultSet в объект Film - private static final RowMapper FILM_ROW_MAPPER = (rs, rowNum) -> Film.builder() - .id(rs.getLong("id")) - .name(rs.getString("name")) - .description(rs.getString("description")) - .releaseDate(rs.getDate("releaseDate").toLocalDate()) - .duration(rs.getInt("duration")) - .likedUsers(new HashSet<>()) // Лайки будут загружаться отдельно - .mpa(Mpa.of(rs.getLong("ratingId"), null)) // Используем статический метод of - .genres(new LinkedHashSet<>()) // Жанры будут загружены отдельно - .build(); + private final String sqlQuery12 = "insert into filmGenre(filmId, genreId) " + "values (?, ?)"; + private final String sqlQuery13 = "update film set " + "name = ?, description = ?, releaseDate = ?, duration = ?, ratingId = ? " + "where id = ?"; + private final String sqlQuery14 = "update film set " + "ratingId = ? " + "where id = ?"; - @Override - public Collection findAll() { - log.info("Processing Get-request..."); - List films = jdbcTemplate.query(sqlQuery1, FILM_ROW_MAPPER); - films.forEach(this::loadAdditionalData); // Загружаем дополнительные данные (лайки, жанры, MPA) - return films; + private Film mapRowToFilm(ResultSet resultSet, int rowNum) throws SQLException { + return Film.builder().id(resultSet.getLong("id")).name(resultSet.getString("name")).description(resultSet.getString("description")).releaseDate(resultSet.getDate("releaseDate").toLocalDate()).duration(resultSet.getInt("duration")).build(); } - @Override - public Film findById(Long id) throws NotFoundException { - if (id == null) { - throw new ValidationException(ExceptionMessages.FILM_ID_CANNOT_BE_NULL); - } - try { - Film film = jdbcTemplate.queryForObject(sqlQuery5, FILM_ROW_MAPPER, id); - if (film != null) { - loadAdditionalData(film); // Загружаем дополнительные данные (лайки, жанры, MPA) + public static class LikedUsersExtractor implements ResultSetExtractor>> { + @Override + public Map> extractData(ResultSet rs) throws SQLException { + Map> data = new LinkedHashMap<>(); + while (rs.next()) { + Long filmId = rs.getLong("filmId"); + data.putIfAbsent(filmId, new HashSet<>()); + Long userId = rs.getLong("userId"); + data.get(filmId).add(userId); } - return film; - } catch (DataAccessException e) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, id), "Список фильмов с рейтингом пуст."); + return data; } } - @Override - public Film create(Film film) throws ValidationException { - validateFilm(film); - - SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate) - .withTableName("film") - .usingGeneratedKeyColumns("id"); - Map parameters = Map.of( - "name", film.getName(), - "description", film.getDescription(), - "releaseDate", film.getReleaseDate(), - "duration", film.getDuration(), - "ratingId", film.getMpa().getId() - ); - long filmId = insert.executeAndReturnKey(parameters).longValue(); - film.setId(filmId); - - // Сохраняем жанры - if (film.getGenres() != null && !film.getGenres().isEmpty()) { - jdbcTemplate.update(sqlQuery11, filmId); // Удаляем старые жанры - for (Genre genre : film.getGenres()) { - jdbcTemplate.update(sqlQuery12, filmId, genre.getId()); // Вставляем новые жанры + public static class FilmGenreExtractor implements ResultSetExtractor>> { + @Override + public Map> extractData(ResultSet rs) throws SQLException { + Map> data = new LinkedHashMap<>(); + while (rs.next()) { + Long filmId = rs.getLong("filmId"); + data.putIfAbsent(filmId, new LinkedHashSet<>()); + Long genreId = rs.getLong("genreId"); + data.get(filmId).add(genreId); } + return data; } - - log.info("Film created: {}", film); - return findById(filmId); } - @Override - public Film update(Film film) throws NotFoundException, ValidationException { - validateFilm(film); - - if (!existsById(film.getId())) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, film.getId()), "Список фильмов с рейтингом пуст."); - } - - jdbcTemplate.update(sqlQuery13, - film.getName(), - film.getDescription(), - film.getReleaseDate(), - film.getDuration(), - film.getMpa().getId(), - film.getId()); - - // Обновляем жанры - if (film.getGenres() != null) { - jdbcTemplate.update(sqlQuery11, film.getId()); // Удаляем старые жанры - for (Genre genre : film.getGenres()) { - jdbcTemplate.update(sqlQuery12, film.getId(), genre.getId()); // Вставляем новые жанры + public static class FilmRatingExtractor implements ResultSetExtractor> { + @Override + public Map extractData(ResultSet rs) throws SQLException { + Map data = new HashMap<>(); + while (rs.next()) { + Long id = rs.getLong("id"); + data.putIfAbsent(id, Long.valueOf(0)); + Long ratingId = rs.getLong("ratingId"); + data.put(id, ratingId); } + return data; } - - log.info("Film with ID = {} updated: {}", film.getId(), film); - return findById(film.getId()); } - public void addLike(Long filmId, Long userId) throws NotFoundException { - if (!existsById(filmId)) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId), "Список фильмов с рейтингом пуст."); - } - if (userStorage.findById(userId) == null) { - throw new NotFoundException(String.format("User with ID = %d not found", userId), "Список фильмов с рейтингом пуст."); + @Override + public List findAll() { + log.info("Обработка Get-запроса..."); + List films = jdbcTemplate.query(sqlQuery1, this::mapRowToFilm); + Map> likedUsers = jdbcTemplate.query(sqlQuery2, new LikedUsersExtractor()); + Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmGenreExtractor()); + Map filmRating = jdbcTemplate.query(sqlQuery4, new FilmRatingExtractor()); + for (Film film : films) { + film.setLikedUsers(likedUsers.get(film.getId())); + film.setGenres(filmGenre.get(film.getId())); + film.setMpa(filmRating.get(film.getId())); } - - jdbcTemplate.update("INSERT INTO likedUsers (filmId, userId) VALUES (?, ?)", filmId, userId); - log.info("User with ID = {} liked the film with ID = {}", userId, filmId); + return films; } - public void removeLike(Long filmId, Long userId) throws NotFoundException { - if (!existsById(filmId)) { - throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId), "Список фильмов с рейтингом пуст."); - } - if (userStorage.findById(userId) == null) { - throw new NotFoundException(String.format("User with ID = %d not found", userId), "Список фильмов с рейтингом пуст."); + @Override + public FilmRequest findById(Long id) throws ConditionsNotMetException, NotFoundException { + log.info("Обработка Get-запроса..."); + if (id != 0 && !id.equals(null)) { + try { + jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); + } catch (DataAccessException e) { + if (e != null) { + log.error("Exception", new NotFoundException(id.toString(), "Идентификатор фильма отсутствует в базе")); + throw new NotFoundException(id.toString(), "Идентификатор фильма отсутствует в базе"); + } + } + Film film = jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); + Map> likedUsers = jdbcTemplate.query(sqlQuery6, new LikedUsersExtractor(), id); + Map> filmGenre = jdbcTemplate.query(sqlQuery7, new FilmGenreExtractor(), id); + Map filmRating = jdbcTemplate.query(sqlQuery8, new FilmRatingExtractor(), id); + film.setLikedUsers(likedUsers.get(id)); + film.setGenres(filmGenre.get(id)); + Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + LinkedHashSet genres = new LinkedHashSet<>(); + if (!filmGenre.isEmpty()) { + for (Long g : filmGenre.get(id)) + genres.add(Genre.of(g, genre.get(g))); + } + film.setMpa(filmRating.get(id)); + return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), Mpa.of(film.getMpa(), rating.get(film.getMpa())), genres); + } else { + log.error("Exception", new ConditionsNotMetException("Идентификатор фильма не может быть нулевой")); + throw new ConditionsNotMetException("Идентификатор фильма не может быть нулевой"); } - - jdbcTemplate.update("DELETE FROM likedUsers WHERE filmId = ? AND userId = ?", filmId, userId); - log.info("User with ID = {} unliked the film with ID = {}", userId, filmId); - } - - public List getTopFilms(int count) { - log.info("Getting top-{} films by number of likes", count); - String sql = "SELECT f.* FROM film f LEFT JOIN likedUsers l ON f.id = l.filmId GROUP BY f.id ORDER BY COUNT(l.userId) DESC LIMIT ?"; - List films = jdbcTemplate.query(sql, FILM_ROW_MAPPER, count); - films.forEach(this::loadAdditionalData); // Загружаем дополнительные данные (лайки, жанры, MPA) - return films; } - private boolean existsById(Long id) { - return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM film WHERE id = ?", Integer.class, id) > 0; + @Override + public Film create(Film film) { + return null; } - private void validateFilm(Film film) throws ValidationException { - if (film.getName() == null || film.getName().isBlank()) { - throw new ValidationException(ExceptionMessages.FILM_NAME_CANNOT_BE_EMPTY); - } - if (film.getDescription() != null && film.getDescription().length() > 200) { - throw new ValidationException(ExceptionMessages.FILM_DESCRIPTION_TOO_LONG); - } - if (film.getReleaseDate() == null || film.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { - throw new ValidationException(ExceptionMessages.FILM_RELEASE_DATE_INVALID); - } - if (film.getDuration() <= 0) { - throw new ValidationException(ExceptionMessages.FILM_DURATION_INVALID); - } + @Override + public Film update(Film film) throws NotFoundException { + return null; } - // Метод для загрузки дополнительных данных (лайки, жанры, MPA) - private void loadAdditionalData(Film film) { - Long filmId = film.getId(); - - // Загружаем лайки - Map> likedUsers = jdbcTemplate.query(sqlQuery6, new LikedUsersExtractor(), filmId); - film.setLikedUsers(likedUsers.getOrDefault(filmId, new HashSet<>())); - - // Загружаем жанры - Map> filmGenres = jdbcTemplate.query(sqlQuery7, new FilmGenreExtractor(), filmId); - LinkedHashSet genres = new LinkedHashSet<>(); - if (filmGenres.containsKey(filmId)) { - for (Long genreId : filmGenres.get(filmId)) { - // Используем статический метод of для создания объекта Genre - genres.add(Genre.of(genreId, null)); // Название жанра будет загружено отдельно - } - } - film.setGenres(genres); - - // Загружаем MPA - Long ratingId = jdbcTemplate.queryForObject(sqlQuery8, Long.class, filmId); - String ratingName = jdbcTemplate.queryForObject("SELECT rating FROM filmrating WHERE id = ?", String.class, ratingId); - film.setMpa(Mpa.of(ratingId, ratingName)); // Используем статический метод of - } + public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException, NullPointerException { + log.info("Обработка Create-запроса..."); + if (buffer.getName() != null && !buffer.getName().isBlank() && !buffer.getName().equals("")) { + if (buffer.getDescription().length() > 200) { + log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); + throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); + } else if (buffer.getReleaseDate().isBefore(ChronoLocalDate.from(LocalDateTime.of(1895, 12, 28, 0, 0, 0)))) { + log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); + throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); + } else if (buffer.getDuration() != null && buffer.getDuration() != 0) { + if (buffer.getDuration() < 0) { + log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); + throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); + } else if (!(buffer.getMpa() > 0 && buffer.getMpa() < 6)) { + log.error("Exception", new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг")); + throw new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг"); + } else { + List genres; + LinkedHashSet genres1 = new LinkedHashSet<>(); + String sqlQuery; + SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); + Long f = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); + Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + if (!buffer.getGenres().equals(List.of("нет жанра"))) { + genres = buffer.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); + for (Long g : genres) { + if (!(g > 0 && g < 7)) { + log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); + throw new NotFoundException(g.toString(), "Некорректный жанр"); + } + } + for (Long g : genres) { + jdbcTemplate.update(sqlQuery12, f, g); + genres1.add(Genre.of(g, genre.get(g))); + } + } + jdbcTemplate.update(sqlQuery14, buffer.getMpa(), f); - // Extractor для лайков - public static class LikedUsersExtractor implements ResultSetExtractor>> { - @Override - public Map> extractData(ResultSet rs) throws SQLException { - Map> likedUsers = new HashMap<>(); - while (rs.next()) { - Long filmId = rs.getLong("filmId"); - Long userId = rs.getLong("userId"); - likedUsers.computeIfAbsent(filmId, k -> new HashSet<>()).add(userId); + FilmRequest film = FilmRequest.of(f, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres1); + return film; + } + } else { + log.error("Exception", new NullPointerException("Продолжительность фильма не может быть нулевой")); + throw new NullPointerException("Продолжительность фильма не может быть нулевой"); } - return likedUsers; + } else { + log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); + throw new ConditionsNotMetException("Название не может быть пустым"); } } - // Extractor для жанров - public static class FilmGenreExtractor implements ResultSetExtractor>> { - @Override - public Map> extractData(ResultSet rs) throws SQLException { - Map> filmGenres = new HashMap<>(); - while (rs.next()) { - Long filmId = rs.getLong("filmId"); - Long genreId = rs.getLong("genreId"); - filmGenres.computeIfAbsent(filmId, k -> new LinkedHashSet<>()).add(genreId); + public FilmRequest update(@Valid Buffer newFilm) throws ConditionsNotMetException, NotFoundException { + log.info("Обработка Put-запроса..."); + if (newFilm.getId() == null) { + log.error("Exception", new ConditionsNotMetException("Id должен быть указан")); + throw new ConditionsNotMetException("Id должен быть указан"); + } else { + FilmRequest oldFilm = findById(newFilm.getId()); + if (newFilm.getName() != null && !newFilm.getName().isBlank()) { + oldFilm.setName(newFilm.getName()); + if (newFilm.getDescription().length() > 200) { + log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); + throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); + } else { + oldFilm.setDescription(newFilm.getDescription()); + if (newFilm.getReleaseDate().isBefore(ChronoLocalDate.from(LocalDateTime.of(1895, 12, 28, 0, 0, 0)))) { + log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); + throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); + } else { + oldFilm.setReleaseDate(newFilm.getReleaseDate()); + if (newFilm.getDuration() != null && newFilm.getDuration() != 0) { + if (newFilm.getDuration() < 0) { + log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); + throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); + } else { + oldFilm.setDuration(newFilm.getDuration()); + if (!(newFilm.getMpa() > 0 && newFilm.getMpa() < 6)) { + log.error("Exception", new NotFoundException(newFilm.getMpa().toString(), "Некорректный рейтинг")); + throw new NotFoundException(newFilm.getMpa().toString(), "Некорректный рейтинг"); + } + LinkedHashSet genres1 = new LinkedHashSet<>(); + Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + if (!newFilm.getGenres().equals(List.of("нет жанра"))) { + List genres = newFilm.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); + for (Long g : genres) { + if (!(g > 0 && g < 7)) { + log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); + throw new NotFoundException(g.toString(), "Некорректный жанр"); + } + } + jdbcTemplate.update(sqlQuery11, oldFilm.getId()); + for (Long g : genres) { + jdbcTemplate.update(sqlQuery12, oldFilm.getId(), g); + genres1.add(Genre.of(g, genre.get(g))); + } + } + if (!oldFilm.getMpa().equals(newFilm.getMpa()) && newFilm.getMpa() > 0 && newFilm.getMpa() < 6) + oldFilm.setMpa(Mpa.of(newFilm.getMpa(), rating.get(newFilm.getMpa()))); + jdbcTemplate.update(sqlQuery13, oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), oldFilm.getMpa().getId(), oldFilm.getId()); + return FilmRequest.of(oldFilm.getId(), oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), new HashSet<>(), oldFilm.getMpa(), genres1); + } + } else { + log.error("Exception", new NullPointerException("Продолжительность фильма не может быть нулевой")); + throw new NullPointerException("Продолжительность фильма не может быть нулевой"); + } + } + } + } else { + log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); + throw new ConditionsNotMetException("Название не может быть пустым"); } - return filmGenres; } } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java index 2241ba3..fa7beb6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java @@ -2,6 +2,7 @@ import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.FilmRequest; import java.util.Collection; @@ -9,7 +10,7 @@ public interface FilmStorage { Collection findAll(); - Film findById(Long id) throws NotFoundException; + FilmRequest findById(Long id) throws NotFoundException; Film create(Film film); From d80198c9da767254988640ca0dc695938a975f39 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 11:18:12 +0500 Subject: [PATCH 013/118] 2 --- .../filmorate/controller/FilmController.java | 61 +++- .../filmorate/storage/film/FilmDbStorage.java | 10 - .../filmorate/storage/film/FilmStorage.java | 12 +- .../filmorate/storage/user/UserDbStorage.java | 323 ++++++++---------- .../filmorate/storage/user/UserStorage.java | 15 +- 5 files changed, 199 insertions(+), 222 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index f8cfd35..97d1c92 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,29 +1,38 @@ package ru.yandex.practicum.filmorate.controller; +import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmRequest; import ru.yandex.practicum.filmorate.service.FilmInterface; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.util.Collection; -import java.util.List; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.*; @RestController @RequestMapping("/films") public class FilmController { - + @Autowired + @Qualifier("FilmDbStorage") private final FilmStorage filmStorage; - private final FilmInterface filmInterface; + + @Autowired + @Qualifier("UserDbStorage") private final UserStorage userStorage; + private final FilmInterface filmInterface; + @Autowired public FilmController(FilmStorage filmStorage, UserStorage userStorage, FilmInterface filmInterface) { this.filmStorage = filmStorage; @@ -32,7 +41,7 @@ public FilmController(FilmStorage filmStorage, UserStorage userStorage, FilmInte } @GetMapping - public Collection findAll() { + public List findAll() { return filmStorage.findAll(); } @@ -43,27 +52,47 @@ public FilmRequest findById(@PathVariable("id") Long id) throws ConditionsNotMet @PostMapping @ResponseStatus(HttpStatus.CREATED) - public Film create(@Valid @RequestBody Film film) throws ConditionsNotMetException, NullPointerException { - return filmStorage.create(film); + public FilmRequest create(@Valid @RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NullPointerException { + String name = objectNode.get("name").asText(); + String description = objectNode.get("description").asText(); + String releaseDate = objectNode.get("releaseDate").asText(); + Integer duration = objectNode.get("duration").asInt(); + List mpa = objectNode.get("mpa").findValuesAsText("id"); + List genres = new ArrayList<>(); + try { + genres = objectNode.get("genres").findValuesAsText("id"); + } catch (NullPointerException e) { + genres = List.of("нет жанра"); + } finally { + return filmStorage.create(Buffer.of(Long.valueOf(0), name, description, LocalDate.parse(releaseDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")), duration, genres, Long.valueOf(mpa.get(0).toString()))); + } } @PutMapping - public Film update(@Valid @RequestBody Film newFilm) throws ConditionsNotMetException, NotFoundException { - return filmStorage.update(newFilm); + public FilmRequest update(@Valid @RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NotFoundException { + Long id = objectNode.get("id").asLong(); + String name = objectNode.get("name").asText(); + String description = objectNode.get("description").asText(); + String releaseDate = objectNode.get("releaseDate").asText(); + Integer duration = objectNode.get("duration").asInt(); + List mpa = objectNode.get("mpa").findValuesAsText("id"); + List genres = new ArrayList<>(); + try { + genres = objectNode.get("genres").findValuesAsText("id"); + } catch (NullPointerException e) { + genres = List.of("нет жанра"); + } finally { + return filmStorage.update(Buffer.of(id, name, description, LocalDate.parse(releaseDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")), duration, genres, Long.valueOf(mpa.get(0).toString()))); + } } @PutMapping("/{id}/like/{userId}") - public FilmRequest addLike(@Valid @RequestBody @PathVariable("id") Long id, @PathVariable("userId") Long userId) throws ConditionsNotMetException { + public FilmRequest addLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) throws ConditionsNotMetException { return filmInterface.addLike(userId, id); } @DeleteMapping("/{id}/like/{userId}") - public FilmRequest delLike(@Valid @RequestBody @PathVariable("id") Long id, @PathVariable("userId") Long userId) throws NotFoundException { + public FilmRequest delLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) throws NotFoundException { return filmInterface.delLike(userId, id); } - - @GetMapping("/popular") - public List viewRaiting(@RequestParam(required = false) Long count) throws NotFoundException { - return filmInterface.viewRaiting(count); - } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index c48ed46..5f044f0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -146,16 +146,6 @@ public FilmRequest findById(Long id) throws ConditionsNotMetException, NotFoundE } } - @Override - public Film create(Film film) { - return null; - } - - @Override - public Film update(Film film) throws NotFoundException { - return null; - } - public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException, NullPointerException { log.info("Обработка Create-запроса..."); if (buffer.getName() != null && !buffer.getName().isBlank() && !buffer.getName().equals("")) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java index fa7beb6..e182c21 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java @@ -1,18 +1,18 @@ package ru.yandex.practicum.filmorate.storage.film; -import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmRequest; -import java.util.Collection; +import java.util.List; public interface FilmStorage { - Collection findAll(); + public List findAll(); - FilmRequest findById(Long id) throws NotFoundException; + public FilmRequest findById(Long id); - Film create(Film film); + public FilmRequest create(Buffer film); - Film update(Film film) throws NotFoundException; + public FilmRequest update(Buffer newFilm); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index d16375a..891c8de 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -1,231 +1,198 @@ package ru.yandex.practicum.filmorate.storage.user; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; -import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; import org.springframework.stereotype.Component; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; import java.sql.ResultSet; import java.sql.SQLException; import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.*; -import java.util.stream.Collectors; -@Component +@Repository @RequiredArgsConstructor -@Slf4j +@Slf4j(topic = "TRACE") +@ConfigurationPropertiesScan +@Component @Qualifier("UserDbStorage") public class UserDbStorage implements UserStorage { + private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private final JdbcTemplate jdbcTemplate; - // SQL-запросы - private static final String FIND_ALL_USERS = "SELECT * FROM users"; - private static final String FIND_USER_BY_ID = "SELECT * FROM users WHERE id = ?"; - private static final String INSERT_USER = "INSERT INTO users (email, login, name, birthday) VALUES (?, ?, ?, ?)"; - private static final String UPDATE_USER = "UPDATE users SET email = ?, login = ?, name = ?, birthday = ? WHERE id = ?"; - private static final String ADD_FRIEND = "INSERT INTO friends (userId, friendId) VALUES (?, ?)"; - private static final String REMOVE_FRIEND = "DELETE FROM friends WHERE userId = ? AND friendId = ?"; - private static final String GET_FRIENDS = "SELECT u.* FROM users u JOIN friends f ON u.id = f.friendId WHERE f.userId = ?"; - private static final String CHECK_DUPLICATE_EMAIL = "SELECT COUNT(*) FROM users WHERE email = ?"; - - // Метод для отображения строки из результата запроса в объект User - private static final RowMapper USER_ROW_MAPPER = (rs, rowNum) -> User.builder() - .id(rs.getLong("id")) - .email(rs.getString("email")) - .login(rs.getString("login")) - .name(rs.getString("name")) - .birthday(rs.getDate("birthday").toLocalDate()) - .friends(new HashSet<>()) - .build(); - - @Override - public Collection findAll() { - log.info("Returning the list of users from the database..."); - return jdbcTemplate.query(FIND_ALL_USERS, USER_ROW_MAPPER); - } - - @Override - public User create(User user) throws ValidationException, DuplicatedDataException { - validateEmail(user.getEmail()); - validateLogin(user.getLogin()); - if (user.getName() == null || user.getName().isBlank()) { - user.setName(user.getLogin()); - } - validateBirthday(user.getBirthday()); - - // Проверка на дублирование email - if (jdbcTemplate.queryForObject(CHECK_DUPLICATE_EMAIL, Integer.class, user.getEmail()) > 0) { - throw new DuplicatedDataException("A user with this email already exists"); - } + private final String sqlQuery1 = "select id, name, email, login, birthday from users"; + private final String sqlQuery2 = "select userId, friendId from friends"; + private final String sqlQuery3 = "select id, name, email, login, birthday from users where id = ?"; + private final String sqlQuery4 = "select email from users"; + private final String sqlQuery5 = "update users set " + "name = ?, email = ?, login = ?, birthday = ? " + "where id = ?"; - // Вставка нового пользователя в базу данных - SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate) - .withTableName("users") - .usingGeneratedKeyColumns("id"); - Map parameters = Map.of( - "email", user.getEmail(), - "login", user.getLogin(), - "name", user.getName(), - "birthday", user.getBirthday() - ); - long userId = insert.executeAndReturnKey(parameters).longValue(); - user.setId(userId); - - log.info("User created: {}", user); - return findById(userId); + private User mapRowToUser(ResultSet resultSet, int rowNum) throws SQLException { + return User.builder().id(resultSet.getLong("id")).name(resultSet.getString("name")).email(resultSet.getString("email")).login(resultSet.getString("login")).birthday(resultSet.getDate("birthday").toLocalDate()).friends(new HashSet<>()).friendRequests(new HashSet<>()).build(); } - @Override - public User update(User newUser) throws NotFoundException, ValidationException { - if (newUser.getId() == null) { - throw new ValidationException("User ID cannot be null"); - } - if (!existsById(newUser.getId())) { - throw new NotFoundException("User with ID = " + newUser.getId() + " not found", "Список фильмов с рейтингом пуст."); - } - - validateEmail(newUser.getEmail()); - validateLogin(newUser.getLogin()); - validateBirthday(newUser.getBirthday()); - - // Обновление пользователя в базе данных - int rowsAffected = jdbcTemplate.update(UPDATE_USER, - newUser.getEmail(), - newUser.getLogin(), - newUser.getName(), - newUser.getBirthday(), - newUser.getId()); - - if (rowsAffected == 0) { - throw new NotFoundException("User with ID = " + newUser.getId() + " not found", "Список фильмов с рейтингом пуст."); + public static class FriendsExtractor implements ResultSetExtractor>> { + @Override + public Map> extractData(ResultSet rs) throws SQLException { + Map> data = new LinkedHashMap<>(); + while (rs.next()) { + Long userId = rs.getLong("userId"); + data.putIfAbsent(userId, new HashSet<>()); + Long friendId = rs.getLong("friendId"); + data.get(userId).add(friendId); + } + return data; } - - log.info("User with ID = {} updated: {}", newUser.getId(), newUser); - return findById(newUser.getId()); } - @Override - public User findById(Long id) throws NotFoundException { - if (id == null) { - throw new ValidationException("ID cannot be null"); - } - try { - return jdbcTemplate.queryForObject(FIND_USER_BY_ID, USER_ROW_MAPPER, id); - } catch (DataAccessException e) { - throw new NotFoundException("User with ID = " + id + " not found", "Список фильмов с рейтингом пуст."); + public static class EmailExtractor implements ResultSetExtractor> { + @Override + public Set extractData(ResultSet rs) throws SQLException { + Set data = new HashSet<>(); + while (rs.next()) { + String email = rs.getString("email"); + data.add(email); + } + return data; } } - @Override - public void addFriend(Long userId, Long friendId) throws NotFoundException { - if (!existsById(userId)) { - throw new NotFoundException("User with ID = " + userId + " not found", "Список фильмов с рейтингом пуст."); - } - if (!existsById(friendId)) { - throw new NotFoundException("User with ID = " + friendId + " not found", "Список фильмов с рейтингом пуст."); + public Collection findAll() { + log.info("Обработка Get-запроса..."); + Collection users = jdbcTemplate.query(sqlQuery1, this::mapRowToUser); + Map> friends = jdbcTemplate.query(sqlQuery2, new FriendsExtractor()); + for (User user : users) { + user.setFriends(friends.get(user.getId())); } - - // Добавление друга - jdbcTemplate.update(ADD_FRIEND, userId, friendId); - log.info("User with ID = {} added as a friend to user with ID = {}", friendId, userId); + return users; } - @Override - public User removeFriend(Long userId, Long friendId) throws NotFoundException { - if (!existsById(userId)) { - throw new NotFoundException("User with ID = " + userId + " not found", "Список фильмов с рейтингом пуст."); - } - if (!existsById(friendId)) { - throw new NotFoundException("User with ID = " + friendId + " not found", "Список фильмов с рейтингом пуст."); + public User findById(Long id) throws ConditionsNotMetException { + log.info("Обработка Get-запроса..."); + if (id != 0 && !id.equals(null)) { + try { + jdbcTemplate.queryForObject(sqlQuery3, this::mapRowToUser, id); + } catch (DataAccessException e) { + if (e != null) { + log.error("Exception", new NotFoundException(id.toString(), "Пользователь с данным идентификатором отсутствует в базе")); + throw new NotFoundException(id.toString(), "Пользователь с данным идентификатором отсутствует в базе"); + } + } + User user = jdbcTemplate.queryForObject(sqlQuery3, this::mapRowToUser, id); + Map> friends = jdbcTemplate.query(sqlQuery2, new FriendsExtractor()); + user.setFriends(friends.get(id)); + return user; + } else { + log.error("Exception", new ConditionsNotMetException("Идентификатор пользователя не может быть нулевой")); + throw new ConditionsNotMetException("Идентификатор пользователя не может быть нулевой"); } - - // Удаление друга - jdbcTemplate.update(REMOVE_FRIEND, userId, friendId); - log.info("User with ID = {} has been removed from friends of user with ID = {}", friendId, userId); - return findById(userId); } - @Override public Collection getFriends(Long id) throws NotFoundException { - if (!existsById(id)) { - throw new NotFoundException("User with ID = " + id + " not found", "Список фильмов с рейтингом пуст."); - } - - return jdbcTemplate.query(GET_FRIENDS, USER_ROW_MAPPER, id); - } - - @Override - public Collection getCommonFriends(Long userId, Long otherUserId) throws NotFoundException { - if (!existsById(userId)) { - throw new NotFoundException("User with ID = " + userId + " not found", "Список фильмов с рейтингом пуст."); - } - if (!existsById(otherUserId)) { - throw new NotFoundException("User with ID = " + otherUserId + " not found", "Список фильмов с рейтингом пуст."); - } - - // Получение общих друзей - Set userFriends = getFriendIds(userId); - Set otherUserFriends = getFriendIds(otherUserId); - - userFriends.retainAll(otherUserFriends); - - return userFriends.stream() - .map(this::findById) - .collect(Collectors.toList()); - } - - private boolean existsById(Long id) { - return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users WHERE id = ?", Integer.class, id) > 0; - } - - private Set getFriendIds(Long userId) { - return jdbcTemplate.queryForList("SELECT friendId FROM friends WHERE userId = ?", Long.class, userId) - .stream() - .collect(Collectors.toSet()); + return List.of(); } - private void validateEmail(String email) throws ValidationException { - if (email == null || email.isBlank() || !email.contains("@") || email.contains(" ") || email.length() < 2) { - throw new ValidationException("Invalid email"); + public User create(@Valid User user) throws ConditionsNotMetException, DuplicatedDataException { + log.info("Обработка Create-запроса..."); + this.duplicateCheck(user); + if (user.getEmail() != null && !user.getEmail().isBlank() && user.getEmail().contains("@") && !user.getEmail().contains(" ") && user.getEmail().length() != 1) { + if (user.getLogin() != null && !user.getLogin().contains(" ") && !user.getLogin().isBlank()) { + if (user.getName() == null || user.getName().isBlank()) { + user.setName(user.getLogin()); + } + + if (user.getBirthday() != null) { + if (user.getBirthday().isAfter(LocalDate.now())) { + log.error("Exception", new ConditionsNotMetException("Дата рождения не может быть в будущем")); + throw new ConditionsNotMetException("Дата рождения не может быть в будущем"); + } else { + SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("users").usingGeneratedKeyColumns("id"); + Long f = simpleJdbcInsert.executeAndReturnKey(user.toMapUser()).longValue(); + return findById(f); + } + } else { + log.error("Exception", new ConditionsNotMetException("Дата рождения не может быть нулевой")); + throw new ConditionsNotMetException("Дата рождения не может быть нулевой"); + } + } else { + log.error("Exception", new ConditionsNotMetException("Логин не может быть пустым и содержать пробелы")); + throw new ConditionsNotMetException("Логин не может быть пустым и содержать пробелы"); + } + } else { + log.error("Exception", new ConditionsNotMetException("Электронная почта не может быть пустой и должна содержать символ @")); + throw new ConditionsNotMetException("Электронная почта не может быть пустой и должна содержать символ @"); } } - private void validateLogin(String login) throws ValidationException { - if (login == null || login.isBlank() || login.contains(" ")) { - throw new ValidationException("Login cannot be empty or contain spaces"); + private void duplicateCheck(User user) throws DuplicatedDataException { + Set emails = jdbcTemplate.query(sqlQuery4, new EmailExtractor()); + if (emails.contains(user.getEmail())) { + log.error("Exception", new DuplicatedDataException("Этот имейл уже используется")); + throw new DuplicatedDataException("Этот имейл уже используется"); } } - private void validateBirthday(LocalDate birthday) throws ValidationException { - if (birthday == null) { - throw new ValidationException("Birthday cannot be null"); - } - if (birthday.isAfter(LocalDate.now())) { - throw new ValidationException("Birthday cannot be in the future"); - } - } - - public static class FriendsExtractor implements ResultSetExtractor>> { - @Override - public Map> extractData(ResultSet rs) throws SQLException { - Map> friends = new HashMap<>(); - while (rs.next()) { - Long userId = rs.getLong("userId"); - Long friendId = rs.getLong("friendId"); - - friends.computeIfAbsent(userId, k -> new HashSet<>()).add(friendId); + public User update(@Valid User newUser) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + if (newUser.getId() == null) { + log.error("Exception", new ConditionsNotMetException("Id должен быть указан")); + throw new ConditionsNotMetException("Id должен быть указан"); + } else { + try { + jdbcTemplate.queryForObject(sqlQuery3, this::mapRowToUser, newUser.getId()); + } catch (DataAccessException e) { + if (e != null) { + log.error("Exception", new NotFoundException(newUser.getId().toString(), "Пользователь с указанным id не найден")); + throw new NotFoundException(newUser.getId().toString(), "Пользователь с указанным id не найден"); + } + } + User oldUser = jdbcTemplate.queryForObject(sqlQuery3, this::mapRowToUser, newUser.getId()); + if (newUser.getEmail() != null && !newUser.getEmail().isBlank() && newUser.getEmail().contains("@") && !newUser.getEmail().contains(" ") && newUser.getEmail().length() != 1) { + if (!newUser.getEmail().equals(oldUser.getEmail())) { + this.duplicateCheck(newUser); + oldUser.setEmail(newUser.getEmail()); + } + + if (newUser.getLogin() != null && !newUser.getLogin().contains(" ") && !newUser.getLogin().isBlank()) { + oldUser.setLogin(newUser.getLogin()); + if (newUser.getName() != null && !newUser.getName().isBlank()) { + oldUser.setName(newUser.getName()); + } else { + oldUser.setName(newUser.getLogin()); + } + + if (newUser.getBirthday() != null) { + if (newUser.getBirthday().isAfter(LocalDate.now())) { + log.error("Exception", new ConditionsNotMetException("Дата рождения не может быть в будущем")); + throw new ConditionsNotMetException("Дата рождения не может быть в будущем"); + } else { + oldUser.setBirthday(newUser.getBirthday()); + jdbcTemplate.update(sqlQuery5, oldUser.getName(), oldUser.getEmail(), oldUser.getLogin(), oldUser.getBirthday(), oldUser.getId()); + return oldUser; + } + } else { + log.error("Exception", new ConditionsNotMetException("Дата рождения не может быть нулевой")); + throw new ConditionsNotMetException("Дата рождения не может быть нулевой"); + } + } else { + log.error("Exception", new ConditionsNotMetException("Логин не может быть пустым и содержать пробелы")); + throw new ConditionsNotMetException("Логин не может быть пустым и содержать пробелы"); + } + } else { + log.error("Exception", new ConditionsNotMetException("Электронная почта не может быть пустой и должна содержать символ @")); + throw new ConditionsNotMetException("Электронная почта не может быть пустой и должна содержать символ @"); } - return friends; } } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserStorage.java index 20710ad..28c4979 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserStorage.java @@ -1,6 +1,5 @@ package ru.yandex.practicum.filmorate.storage.user; -import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.User; import java.util.Collection; @@ -9,17 +8,9 @@ public interface UserStorage { Collection findAll(); - User create(User user); - - User update(User user) throws NotFoundException; - - void addFriend(Long userId, Long friendId) throws NotFoundException; + User findById(Long id); - User removeFriend(Long userId, Long friendId) throws NotFoundException; - - Collection getCommonFriends(Long userId, Long otherUserId) throws NotFoundException; - - User findById(Long id) throws NotFoundException; + User create(User user); - Collection getFriends(Long id) throws NotFoundException; + User update(User newUser); } \ No newline at end of file From cb61ead99374247ad3597ae55544348311f24689 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 11:35:48 +0500 Subject: [PATCH 014/118] =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0?= =?UTF-8?q?=D0=B5=D0=BC=20=D1=81=20=D0=B6=D0=B0=D0=BD=D1=80=D0=B0=D0=BC?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 5 +++ .../filmorate/controller/GenreController.java | 33 +++++++++++++++++ .../filmorate/service/FilmInterface.java | 5 ++- .../filmorate/service/GenreService.java | 27 ++++++++++++++ .../storage/film/GenreDbStorage.java | 35 +++++++++++++++++++ 5 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/film/GenreDbStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 97d1c92..f6c868f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -95,4 +95,9 @@ public FilmRequest addLike(@Valid @PathVariable("id") Long id, @PathVariable("us public FilmRequest delLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) throws NotFoundException { return filmInterface.delLike(userId, id); } + + @GetMapping("/popular") + public LinkedHashSet viewRaiting(@RequestParam(required = false) Long count) throws NotFoundException { + return filmInterface.viewRating(count); + } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java new file mode 100644 index 0000000..c4aa356 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java @@ -0,0 +1,33 @@ +package ru.yandex.practicum.filmorate.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.yandex.practicum.filmorate.model.Genre; +import ru.yandex.practicum.filmorate.service.GenreService; + +import java.util.List; + +@RestController +@RequestMapping("/genres") +public class GenreController { + + private final GenreService genreService; + + @Autowired + public GenreController(GenreService genreService) { + this.genreService = genreService; + } + + @GetMapping("/{id}") + public Genre getGenreById(@PathVariable Long id) { + return genreService.getGenreById(id); + } + + @GetMapping + public List getAllGenres() { + return genreService.getAllGenres(); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmInterface.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmInterface.java index 2ef7072..57cc56a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmInterface.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmInterface.java @@ -1,14 +1,13 @@ package ru.yandex.practicum.filmorate.service; -import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmRequest; -import java.util.List; +import java.util.LinkedHashSet; public interface FilmInterface { FilmRequest addLike(Long idUser, Long idFilm); FilmRequest delLike(Long idUser, Long idFilm); - List viewRaiting(Long count); + LinkedHashSet viewRating(Long count); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java new file mode 100644 index 0000000..1079bdf --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java @@ -0,0 +1,27 @@ +package ru.yandex.practicum.filmorate.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.model.Genre; +import ru.yandex.practicum.filmorate.storage.film.GenreDbStorage; + +import java.util.List; + +@Service +public class GenreService { + + private final GenreDbStorage genreStorage; + + @Autowired + public GenreService(GenreDbStorage genreStorage) { + this.genreStorage = genreStorage; + } + + public Genre getGenreById(Long id) { + return genreStorage.getGenreById(id); + } + + public List getAllGenres() { + return genreStorage.getAllGenres(); + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/GenreDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/GenreDbStorage.java new file mode 100644 index 0000000..9b9584e --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/GenreDbStorage.java @@ -0,0 +1,35 @@ +package ru.yandex.practicum.filmorate.storage.film; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Genre; + +import java.util.List; + +@Repository +public class GenreDbStorage { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public GenreDbStorage(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public Genre getGenreById(Long id) { + String sql = "SELECT id, name FROM genre WHERE id = ?"; + try { + return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> Genre.of(rs.getLong("id"), rs.getString("name")), id); + } catch (DataAccessException e) { + throw new NotFoundException(id.toString(), "Genre with id " + id + " not found"); + } + } + + public List getAllGenres() { + String sql = "SELECT id, name FROM genre"; + return jdbcTemplate.query(sql, (rs, rowNum) -> Genre.of(rs.getLong("id"), rs.getString("name"))); + } +} \ No newline at end of file From 620288cabb6c4f41fdef6c27c76ed0656c518a67 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 12:14:35 +0500 Subject: [PATCH 015/118] =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0?= =?UTF-8?q?=D0=B5=D0=BC=20=D1=81=20=D0=BC=D0=BF=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/MpaController.java | 34 ++++++++++++++++++ .../filmorate/service/MpaService.java | 27 ++++++++++++++ .../filmorate/storage/film/MpaDbStorage.java | 35 +++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/film/MpaDbStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java new file mode 100644 index 0000000..ddf9c92 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java @@ -0,0 +1,34 @@ +package ru.yandex.practicum.filmorate.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.yandex.practicum.filmorate.model.Mpa; +import ru.yandex.practicum.filmorate.service.MpaService; + +import java.util.List; + +@RestController +@RequestMapping("/mpa") +public class MpaController { + + private final MpaService mpaService; + + @Autowired + public MpaController(MpaService mpaService) { + this.mpaService = mpaService; + } + + @GetMapping("/{id}") + public Mpa getMpaById(@PathVariable Long id) { + return mpaService.getMpaById(id); + } + + @GetMapping + public List getAllMpa() { + return mpaService.getAllMpa(); + } +} + diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java new file mode 100644 index 0000000..312ea3d --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java @@ -0,0 +1,27 @@ +package ru.yandex.practicum.filmorate.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.model.Mpa; +import ru.yandex.practicum.filmorate.storage.film.MpaDbStorage; + +import java.util.List; + +@Service +public class MpaService { + + private final MpaDbStorage mpaStorage; + + @Autowired + public MpaService(MpaDbStorage mpaStorage) { + this.mpaStorage = mpaStorage; + } + + public Mpa getMpaById(Long id) { + return mpaStorage.getMpaById(id); + } + + public List getAllMpa() { + return mpaStorage.getAllMpa(); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/MpaDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/MpaDbStorage.java new file mode 100644 index 0000000..08036ab --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/MpaDbStorage.java @@ -0,0 +1,35 @@ +package ru.yandex.practicum.filmorate.storage.film; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Mpa; + +import java.util.List; + +@Repository +public class MpaDbStorage { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public MpaDbStorage(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public Mpa getMpaById(Long id) { + String sql = "SELECT id, rating FROM filmrating WHERE id = ?"; + try { + return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> Mpa.of(rs.getLong("id"), rs.getString("rating")), id); + } catch (DataAccessException e) { + throw new NotFoundException(id.toString(), "MPA with id " + id + " not found"); + } + } + + public List getAllMpa() { + String sql = "SELECT id, rating FROM filmrating"; + return jdbcTemplate.query(sql, (rs, rowNum) -> Mpa.of(rs.getLong("id"), rs.getString("rating"))); + } +} \ No newline at end of file From 6b1bc34ee25ccb6d38afb1e69aeac13015e999d5 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 12:46:27 +0500 Subject: [PATCH 016/118] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA?= =?UTF-8?q?=D1=83=20=D0=B5=D1=89=D0=B5=20=D0=BE=D0=B4=D0=BD=D0=BE=D0=B9=20?= =?UTF-8?q?=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/controller/ErrorHandler.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java index 65e9aa5..b019856 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java @@ -6,6 +6,7 @@ import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; +import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.exception.ValidationException; @@ -49,4 +50,10 @@ public ResponseEntity> handleMethodArgumentNotValidException return ResponseEntity.status(HttpStatus.BAD_REQUEST) .body(Map.of("error", message)); } + + @ExceptionHandler(ConditionsNotMetException.class) + public ResponseEntity> handleConditionsNotMetException(ConditionsNotMetException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(Map.of("error", e.getMessage())); + } } \ No newline at end of file From 9fc8e20844c08a8ff0aeac98acd0f888d16e6544 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 12:55:09 +0500 Subject: [PATCH 017/118] =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D1=8B=D1=82=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ErrorHandler.java | 6 +- .../filmorate/storage/user/UserDbStorage.java | 157 +++++++++--------- 2 files changed, 84 insertions(+), 79 deletions(-) rename src/main/java/ru/yandex/practicum/filmorate/{controller => exception}/ErrorHandler.java (87%) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java similarity index 87% rename from src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java rename to src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java index b019856..8afe7ff 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java @@ -1,4 +1,4 @@ -package ru.yandex.practicum.filmorate.controller; +package ru.yandex.practicum.filmorate.exception; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -6,10 +6,6 @@ import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; -import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; -import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; -import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.exception.ValidationException; import java.util.Map; diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 891c8de..a7e3b93 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -14,6 +14,7 @@ import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; import java.sql.ResultSet; @@ -104,36 +105,43 @@ public Collection getFriends(Long id) throws NotFoundException { return List.of(); } - public User create(@Valid User user) throws ConditionsNotMetException, DuplicatedDataException { + public User create(@Valid User user) throws DuplicatedDataException, ValidationException { log.info("Обработка Create-запроса..."); - this.duplicateCheck(user); - if (user.getEmail() != null && !user.getEmail().isBlank() && user.getEmail().contains("@") && !user.getEmail().contains(" ") && user.getEmail().length() != 1) { - if (user.getLogin() != null && !user.getLogin().contains(" ") && !user.getLogin().isBlank()) { - if (user.getName() == null || user.getName().isBlank()) { - user.setName(user.getLogin()); - } - if (user.getBirthday() != null) { - if (user.getBirthday().isAfter(LocalDate.now())) { - log.error("Exception", new ConditionsNotMetException("Дата рождения не может быть в будущем")); - throw new ConditionsNotMetException("Дата рождения не может быть в будущем"); - } else { - SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("users").usingGeneratedKeyColumns("id"); - Long f = simpleJdbcInsert.executeAndReturnKey(user.toMapUser()).longValue(); - return findById(f); - } - } else { - log.error("Exception", new ConditionsNotMetException("Дата рождения не может быть нулевой")); - throw new ConditionsNotMetException("Дата рождения не может быть нулевой"); - } - } else { - log.error("Exception", new ConditionsNotMetException("Логин не может быть пустым и содержать пробелы")); - throw new ConditionsNotMetException("Логин не может быть пустым и содержать пробелы"); - } - } else { - log.error("Exception", new ConditionsNotMetException("Электронная почта не может быть пустой и должна содержать символ @")); - throw new ConditionsNotMetException("Электронная почта не может быть пустой и должна содержать символ @"); + // Проверка на дубликат email + duplicateCheck(user); + + // Проверка email + if (user.getEmail() == null || user.getEmail().isBlank() || !user.getEmail().contains("@")) { + throw new ValidationException("Электронная почта не может быть пустой и должна содержать символ @"); } + + // Проверка логина + if (user.getLogin() == null || user.getLogin().isBlank() || user.getLogin().contains(" ")) { + throw new ValidationException("Логин не может быть пустым и содержать пробелы"); + } + + // Проверка имени + if (user.getName() == null || user.getName().isBlank()) { + user.setName(user.getLogin()); + } + + // Проверка даты рождения + if (user.getBirthday() == null) { + throw new ValidationException("Дата рождения не может быть нулевой"); + } + if (user.getBirthday().isAfter(LocalDate.now())) { + throw new ValidationException("Дата рождения не может быть в будущем"); + } + + // Создание пользователя + SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate) + .withTableName("users") + .usingGeneratedKeyColumns("id"); + Long id = simpleJdbcInsert.executeAndReturnKey(user.toMapUser()).longValue(); + user.setId(id); + + return user; } private void duplicateCheck(User user) throws DuplicatedDataException { @@ -144,55 +152,56 @@ private void duplicateCheck(User user) throws DuplicatedDataException { } } - public User update(@Valid User newUser) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + public User update(@Valid User newUser) throws NotFoundException, DuplicatedDataException, ValidationException { + log.info("Обработка Update-запроса..."); + + // Проверка на наличие ID if (newUser.getId() == null) { - log.error("Exception", new ConditionsNotMetException("Id должен быть указан")); - throw new ConditionsNotMetException("Id должен быть указан"); - } else { - try { - jdbcTemplate.queryForObject(sqlQuery3, this::mapRowToUser, newUser.getId()); - } catch (DataAccessException e) { - if (e != null) { - log.error("Exception", new NotFoundException(newUser.getId().toString(), "Пользователь с указанным id не найден")); - throw new NotFoundException(newUser.getId().toString(), "Пользователь с указанным id не найден"); - } - } - User oldUser = jdbcTemplate.queryForObject(sqlQuery3, this::mapRowToUser, newUser.getId()); - if (newUser.getEmail() != null && !newUser.getEmail().isBlank() && newUser.getEmail().contains("@") && !newUser.getEmail().contains(" ") && newUser.getEmail().length() != 1) { - if (!newUser.getEmail().equals(oldUser.getEmail())) { - this.duplicateCheck(newUser); - oldUser.setEmail(newUser.getEmail()); - } + throw new ValidationException("Id должен быть указан"); + } - if (newUser.getLogin() != null && !newUser.getLogin().contains(" ") && !newUser.getLogin().isBlank()) { - oldUser.setLogin(newUser.getLogin()); - if (newUser.getName() != null && !newUser.getName().isBlank()) { - oldUser.setName(newUser.getName()); - } else { - oldUser.setName(newUser.getLogin()); - } - - if (newUser.getBirthday() != null) { - if (newUser.getBirthday().isAfter(LocalDate.now())) { - log.error("Exception", new ConditionsNotMetException("Дата рождения не может быть в будущем")); - throw new ConditionsNotMetException("Дата рождения не может быть в будущем"); - } else { - oldUser.setBirthday(newUser.getBirthday()); - jdbcTemplate.update(sqlQuery5, oldUser.getName(), oldUser.getEmail(), oldUser.getLogin(), oldUser.getBirthday(), oldUser.getId()); - return oldUser; - } - } else { - log.error("Exception", new ConditionsNotMetException("Дата рождения не может быть нулевой")); - throw new ConditionsNotMetException("Дата рождения не может быть нулевой"); - } - } else { - log.error("Exception", new ConditionsNotMetException("Логин не может быть пустым и содержать пробелы")); - throw new ConditionsNotMetException("Логин не может быть пустым и содержать пробелы"); - } - } else { - log.error("Exception", new ConditionsNotMetException("Электронная почта не может быть пустой и должна содержать символ @")); - throw new ConditionsNotMetException("Электронная почта не может быть пустой и должна содержать символ @"); - } + // Поиск существующего пользователя + User oldUser = findById(newUser.getId()); + if (oldUser == null) { + throw new NotFoundException("oldUser", "Пользователь с указанным id не найден"); + } + + // Проверка email + if (newUser.getEmail() == null || newUser.getEmail().isBlank() || !newUser.getEmail().contains("@")) { + throw new ValidationException("Электронная почта не может быть пустой и должна содержать символ @"); + } + + // Проверка на дубликат email + if (!newUser.getEmail().equals(oldUser.getEmail())) { + duplicateCheck(newUser); } + + // Проверка логина + if (newUser.getLogin() == null || newUser.getLogin().isBlank() || newUser.getLogin().contains(" ")) { + throw new ValidationException("Логин не может быть пустым и содержать пробелы"); + } + + // Проверка имени + if (newUser.getName() == null || newUser.getName().isBlank()) { + newUser.setName(newUser.getLogin()); + } + + // Проверка даты рождения + if (newUser.getBirthday() == null) { + throw new ValidationException("Дата рождения не может быть нулевой"); + } + if (newUser.getBirthday().isAfter(LocalDate.now())) { + throw new ValidationException("Дата рождения не может быть в будущем"); + } + + // Обновление пользователя + jdbcTemplate.update(sqlQuery5, + newUser.getName(), + newUser.getEmail(), + newUser.getLogin(), + newUser.getBirthday(), + newUser.getId()); + + return newUser; } } \ No newline at end of file From cc7151ad10164eef9e85d3d96729a9804a1a1527 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 13:15:41 +0500 Subject: [PATCH 018/118] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D0=B0=20=D1=84=D0=B8=D0=BB=D1=8C=D0=BC=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 227 ++++++++++-------- 1 file changed, 128 insertions(+), 99 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 5f044f0..f28885f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -19,6 +19,7 @@ import java.sql.ResultSet; import java.sql.SQLException; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.chrono.ChronoLocalDate; import java.time.format.DateTimeFormatter; @@ -148,117 +149,145 @@ public FilmRequest findById(Long id) throws ConditionsNotMetException, NotFoundE public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException, NullPointerException { log.info("Обработка Create-запроса..."); - if (buffer.getName() != null && !buffer.getName().isBlank() && !buffer.getName().equals("")) { - if (buffer.getDescription().length() > 200) { - log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); - throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); - } else if (buffer.getReleaseDate().isBefore(ChronoLocalDate.from(LocalDateTime.of(1895, 12, 28, 0, 0, 0)))) { - log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); - throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); - } else if (buffer.getDuration() != null && buffer.getDuration() != 0) { - if (buffer.getDuration() < 0) { - log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); - throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); - } else if (!(buffer.getMpa() > 0 && buffer.getMpa() < 6)) { - log.error("Exception", new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг")); - throw new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг"); - } else { - List genres; - LinkedHashSet genres1 = new LinkedHashSet<>(); - String sqlQuery; - SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); - Long f = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); - Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); - if (!buffer.getGenres().equals(List.of("нет жанра"))) { - genres = buffer.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); - for (Long g : genres) { - if (!(g > 0 && g < 7)) { - log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); - throw new NotFoundException(g.toString(), "Некорректный жанр"); - } - } - for (Long g : genres) { - jdbcTemplate.update(sqlQuery12, f, g); - genres1.add(Genre.of(g, genre.get(g))); - } - } - jdbcTemplate.update(sqlQuery14, buffer.getMpa(), f); - - FilmRequest film = FilmRequest.of(f, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres1); - return film; - } - } else { - log.error("Exception", new NullPointerException("Продолжительность фильма не может быть нулевой")); - throw new NullPointerException("Продолжительность фильма не может быть нулевой"); - } - } else { + + // Проверка названия фильма + if (buffer.getName() == null || buffer.getName().isBlank()) { log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); throw new ConditionsNotMetException("Название не может быть пустым"); } + + // Проверка описания фильма + if (buffer.getDescription() == null || buffer.getDescription().length() > 200) { + log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); + throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); + } + + // Проверка даты выпуска + if (buffer.getReleaseDate() == null || buffer.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { + log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); + throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); + } + + // Проверка продолжительности фильма + if (buffer.getDuration() == null || buffer.getDuration() <= 0) { + log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); + throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); + } + + // Проверка рейтинга MPA + if (buffer.getMpa() == null || buffer.getMpa() < 1 || buffer.getMpa() > 5) { + log.error("Exception", new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг")); + throw new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг"); + } + + // Создание фильма + List genres; + LinkedHashSet genres1 = new LinkedHashSet<>(); + SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); + Long f = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); + Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + + // Проверка и добавление жанров + if (!buffer.getGenres().equals(List.of("нет жанра"))) { + genres = buffer.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); + for (Long g : genres) { + if (g < 1 || g > 6) { + log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); + throw new NotFoundException(g.toString(), "Некорректный жанр"); + } + } + for (Long g : genres) { + jdbcTemplate.update(sqlQuery12, f, g); + genres1.add(Genre.of(g, genre.get(g))); + } + } + + // Обновление рейтинга MPA + jdbcTemplate.update(sqlQuery14, buffer.getMpa(), f); + + // Создание объекта FilmRequest + FilmRequest film = FilmRequest.of(f, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres1); + return film; } public FilmRequest update(@Valid Buffer newFilm) throws ConditionsNotMetException, NotFoundException { log.info("Обработка Put-запроса..."); + + // Проверка ID фильма if (newFilm.getId() == null) { log.error("Exception", new ConditionsNotMetException("Id должен быть указан")); throw new ConditionsNotMetException("Id должен быть указан"); - } else { - FilmRequest oldFilm = findById(newFilm.getId()); - if (newFilm.getName() != null && !newFilm.getName().isBlank()) { - oldFilm.setName(newFilm.getName()); - if (newFilm.getDescription().length() > 200) { - log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); - throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); - } else { - oldFilm.setDescription(newFilm.getDescription()); - if (newFilm.getReleaseDate().isBefore(ChronoLocalDate.from(LocalDateTime.of(1895, 12, 28, 0, 0, 0)))) { - log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); - throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); - } else { - oldFilm.setReleaseDate(newFilm.getReleaseDate()); - if (newFilm.getDuration() != null && newFilm.getDuration() != 0) { - if (newFilm.getDuration() < 0) { - log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); - throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); - } else { - oldFilm.setDuration(newFilm.getDuration()); - if (!(newFilm.getMpa() > 0 && newFilm.getMpa() < 6)) { - log.error("Exception", new NotFoundException(newFilm.getMpa().toString(), "Некорректный рейтинг")); - throw new NotFoundException(newFilm.getMpa().toString(), "Некорректный рейтинг"); - } - LinkedHashSet genres1 = new LinkedHashSet<>(); - Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); - if (!newFilm.getGenres().equals(List.of("нет жанра"))) { - List genres = newFilm.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); - for (Long g : genres) { - if (!(g > 0 && g < 7)) { - log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); - throw new NotFoundException(g.toString(), "Некорректный жанр"); - } - } - jdbcTemplate.update(sqlQuery11, oldFilm.getId()); - for (Long g : genres) { - jdbcTemplate.update(sqlQuery12, oldFilm.getId(), g); - genres1.add(Genre.of(g, genre.get(g))); - } - } - if (!oldFilm.getMpa().equals(newFilm.getMpa()) && newFilm.getMpa() > 0 && newFilm.getMpa() < 6) - oldFilm.setMpa(Mpa.of(newFilm.getMpa(), rating.get(newFilm.getMpa()))); - jdbcTemplate.update(sqlQuery13, oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), oldFilm.getMpa().getId(), oldFilm.getId()); - return FilmRequest.of(oldFilm.getId(), oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), new HashSet<>(), oldFilm.getMpa(), genres1); - } - } else { - log.error("Exception", new NullPointerException("Продолжительность фильма не может быть нулевой")); - throw new NullPointerException("Продолжительность фильма не может быть нулевой"); - } - } + } + + // Проверка названия фильма + if (newFilm.getName() == null || newFilm.getName().isBlank()) { + log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); + throw new ConditionsNotMetException("Название не может быть пустым"); + } + + // Проверка описания фильма + if (newFilm.getDescription() == null || newFilm.getDescription().length() > 200) { + log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); + throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); + } + + // Проверка даты выпуска + if (newFilm.getReleaseDate() == null || newFilm.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { + log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); + throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); + } + + // Проверка продолжительности фильма + if (newFilm.getDuration() == null || newFilm.getDuration() <= 0) { + log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); + throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); + } + + // Проверка рейтинга MPA + if (newFilm.getMpa() == null || newFilm.getMpa() < 1 || newFilm.getMpa() > 5) { + log.error("Exception", new NotFoundException(newFilm.getMpa().toString(), "Некорректный рейтинг")); + throw new NotFoundException(newFilm.getMpa().toString(), "Некорректный рейтинг"); + } + + // Получение старого фильма + FilmRequest oldFilm = findById(newFilm.getId()); + + // Обновление данных фильма + oldFilm.setName(newFilm.getName()); + oldFilm.setDescription(newFilm.getDescription()); + oldFilm.setReleaseDate(newFilm.getReleaseDate()); + oldFilm.setDuration(newFilm.getDuration()); + + // Обновление жанров + LinkedHashSet genres1 = new LinkedHashSet<>(); + Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + + if (!newFilm.getGenres().equals(List.of("нет жанра"))) { + List genres = newFilm.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); + for (Long g : genres) { + if (g < 1 || g > 6) { + log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); + throw new NotFoundException(g.toString(), "Некорректный жанр"); } - } else { - log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); - throw new ConditionsNotMetException("Название не может быть пустым"); } + jdbcTemplate.update(sqlQuery11, oldFilm.getId()); + for (Long g : genres) { + jdbcTemplate.update(sqlQuery12, oldFilm.getId(), g); + genres1.add(Genre.of(g, genre.get(g))); + } + } + + // Обновление рейтинга MPA + if (!oldFilm.getMpa().equals(newFilm.getMpa())) { + oldFilm.setMpa(Mpa.of(newFilm.getMpa(), rating.get(newFilm.getMpa()))); } + + // Обновление фильма в базе данных + jdbcTemplate.update(sqlQuery13, oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), oldFilm.getMpa().getId(), oldFilm.getId()); + + // Возврат обновленного фильма + return FilmRequest.of(oldFilm.getId(), oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), new HashSet<>(), oldFilm.getMpa(), genres1); } } \ No newline at end of file From 6dbf4f56fb877b2020c2a2037bf2acff9792e7ea Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 13:18:21 +0500 Subject: [PATCH 019/118] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=D1=8C=20=D1=81?= =?UTF-8?q?=D1=82=D0=B8=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/film/FilmDbStorage.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index f28885f..9e2a80d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -20,8 +20,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.chrono.ChronoLocalDate; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; From c8b6ad50e94ad3100daf8e841c4e6562ccd2e633 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 14:41:47 +0500 Subject: [PATCH 020/118] aaaa --- .../filmorate/storage/film/FilmDbStorage.java | 61 +++++++++++++++---- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 9e2a80d..51a7583 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -145,56 +145,73 @@ public FilmRequest findById(Long id) throws ConditionsNotMetException, NotFoundE } } + @Override public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException, NullPointerException { log.info("Обработка Create-запроса..."); + // Создаем объект Film на основе данных из Buffer + Film film = Film.builder() + .name(buffer.getName()) + .description(buffer.getDescription()) + .releaseDate(buffer.getReleaseDate()) + .duration(buffer.getDuration()) + .mpa(buffer.getMpa()) + .genres(convertGenres((LinkedHashSet) buffer.getGenres())) // Преобразуем жанры + .build(); + // Проверка названия фильма - if (buffer.getName() == null || buffer.getName().isBlank()) { + if (film.getName() == null || film.getName().isBlank()) { log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); throw new ConditionsNotMetException("Название не может быть пустым"); } // Проверка описания фильма - if (buffer.getDescription() == null || buffer.getDescription().length() > 200) { + if (film.getDescription() == null || film.getDescription().length() > 200) { log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); } // Проверка даты выпуска - if (buffer.getReleaseDate() == null || buffer.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { + if (film.getReleaseDate() == null || film.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); } // Проверка продолжительности фильма - if (buffer.getDuration() == null || buffer.getDuration() <= 0) { + if (film.getDuration() == null || film.getDuration() <= 0) { log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); } // Проверка рейтинга MPA - if (buffer.getMpa() == null || buffer.getMpa() < 1 || buffer.getMpa() > 5) { - log.error("Exception", new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг")); - throw new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг"); + if (film.getMpa() == null || film.getMpa() < 1 || film.getMpa() > 5) { + log.error("Exception", new NotFoundException(film.getMpa().toString(), "Некорректный рейтинг")); + throw new NotFoundException(film.getMpa().toString(), "Некорректный рейтинг"); } - // Создание фильма + // Создание фильма в базе данных List genres; LinkedHashSet genres1 = new LinkedHashSet<>(); SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); Long f = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); + + // Получение списка жанров Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); // Проверка и добавление жанров if (!buffer.getGenres().equals(List.of("нет жанра"))) { - genres = buffer.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); + genres = buffer.getGenres().stream() + .map(Long::parseLong) // Преобразуем строки в числа + .collect(Collectors.toList()); + for (Long g : genres) { if (g < 1 || g > 6) { log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); throw new NotFoundException(g.toString(), "Некорректный жанр"); } } + for (Long g : genres) { jdbcTemplate.update(sqlQuery12, f, g); genres1.add(Genre.of(g, genre.get(g))); @@ -202,11 +219,31 @@ public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException } // Обновление рейтинга MPA - jdbcTemplate.update(sqlQuery14, buffer.getMpa(), f); + jdbcTemplate.update(sqlQuery14, film.getMpa(), f); // Создание объекта FilmRequest - FilmRequest film = FilmRequest.of(f, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres1); - return film; + FilmRequest filmRequest = FilmRequest.of( + f, + film.getName(), + film.getDescription(), + film.getReleaseDate(), + film.getDuration(), + new HashSet<>(), + Mpa.of(film.getMpa(), rating.get(film.getMpa())), + genres1 + ); + + return filmRequest; + } + + // Метод для конвертации LinkedHashSet в LinkedHashSet + private LinkedHashSet convertGenres(LinkedHashSet genres) { + if (genres == null || genres.isEmpty()) { + return null; + } + return genres.stream() + .map(Long::parseLong) // Преобразуем строки в числа + .collect(Collectors.toCollection(LinkedHashSet::new)); // Создаем новый LinkedHashSet } public FilmRequest update(@Valid Buffer newFilm) throws ConditionsNotMetException, NotFoundException { From 685fb6393a1288ff71367f7414f5485df3e641fd Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 14:44:42 +0500 Subject: [PATCH 021/118] =?UTF-8?q?=D0=B2=D1=81=D0=B5=20=D0=B8=D0=B7=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BD=D0=B0=D0=B7=D0=B0?= =?UTF-8?q?=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 61 ++++--------------- 1 file changed, 12 insertions(+), 49 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 51a7583..9e2a80d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -145,73 +145,56 @@ public FilmRequest findById(Long id) throws ConditionsNotMetException, NotFoundE } } - @Override public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException, NullPointerException { log.info("Обработка Create-запроса..."); - // Создаем объект Film на основе данных из Buffer - Film film = Film.builder() - .name(buffer.getName()) - .description(buffer.getDescription()) - .releaseDate(buffer.getReleaseDate()) - .duration(buffer.getDuration()) - .mpa(buffer.getMpa()) - .genres(convertGenres((LinkedHashSet) buffer.getGenres())) // Преобразуем жанры - .build(); - // Проверка названия фильма - if (film.getName() == null || film.getName().isBlank()) { + if (buffer.getName() == null || buffer.getName().isBlank()) { log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); throw new ConditionsNotMetException("Название не может быть пустым"); } // Проверка описания фильма - if (film.getDescription() == null || film.getDescription().length() > 200) { + if (buffer.getDescription() == null || buffer.getDescription().length() > 200) { log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); } // Проверка даты выпуска - if (film.getReleaseDate() == null || film.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { + if (buffer.getReleaseDate() == null || buffer.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); } // Проверка продолжительности фильма - if (film.getDuration() == null || film.getDuration() <= 0) { + if (buffer.getDuration() == null || buffer.getDuration() <= 0) { log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); } // Проверка рейтинга MPA - if (film.getMpa() == null || film.getMpa() < 1 || film.getMpa() > 5) { - log.error("Exception", new NotFoundException(film.getMpa().toString(), "Некорректный рейтинг")); - throw new NotFoundException(film.getMpa().toString(), "Некорректный рейтинг"); + if (buffer.getMpa() == null || buffer.getMpa() < 1 || buffer.getMpa() > 5) { + log.error("Exception", new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг")); + throw new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг"); } - // Создание фильма в базе данных + // Создание фильма List genres; LinkedHashSet genres1 = new LinkedHashSet<>(); SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); Long f = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); - - // Получение списка жанров Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); // Проверка и добавление жанров if (!buffer.getGenres().equals(List.of("нет жанра"))) { - genres = buffer.getGenres().stream() - .map(Long::parseLong) // Преобразуем строки в числа - .collect(Collectors.toList()); - + genres = buffer.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); for (Long g : genres) { if (g < 1 || g > 6) { log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); throw new NotFoundException(g.toString(), "Некорректный жанр"); } } - for (Long g : genres) { jdbcTemplate.update(sqlQuery12, f, g); genres1.add(Genre.of(g, genre.get(g))); @@ -219,31 +202,11 @@ public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException } // Обновление рейтинга MPA - jdbcTemplate.update(sqlQuery14, film.getMpa(), f); + jdbcTemplate.update(sqlQuery14, buffer.getMpa(), f); // Создание объекта FilmRequest - FilmRequest filmRequest = FilmRequest.of( - f, - film.getName(), - film.getDescription(), - film.getReleaseDate(), - film.getDuration(), - new HashSet<>(), - Mpa.of(film.getMpa(), rating.get(film.getMpa())), - genres1 - ); - - return filmRequest; - } - - // Метод для конвертации LinkedHashSet в LinkedHashSet - private LinkedHashSet convertGenres(LinkedHashSet genres) { - if (genres == null || genres.isEmpty()) { - return null; - } - return genres.stream() - .map(Long::parseLong) // Преобразуем строки в числа - .collect(Collectors.toCollection(LinkedHashSet::new)); // Создаем новый LinkedHashSet + FilmRequest film = FilmRequest.of(f, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres1); + return film; } public FilmRequest update(@Valid Buffer newFilm) throws ConditionsNotMetException, NotFoundException { From c63d6fe9d8bd2538a8f895b70b54a02916d6bbce Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 15:11:49 +0500 Subject: [PATCH 022/118] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=87?= =?UTF-8?q?=D0=B8=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/GlobalExceptionHandler.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java b/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..285b907 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java @@ -0,0 +1,22 @@ +package ru.yandex.practicum.filmorate.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +import java.util.Map; + +@ControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(ConditionsNotMetException.class) + public ResponseEntity> handleConditionsNotMetException(ConditionsNotMetException ex) { + return ResponseEntity.badRequest().body(Map.of("error", ex.getMessage())); + } + + @ExceptionHandler(NotFoundException.class) + public ResponseEntity> handleNotFoundException(NotFoundException ex) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of("error", ex.getMessage())); + } +} From fa2d755a29a49e06a1d8e4557c21d2ca74add04b Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 15:22:43 +0500 Subject: [PATCH 023/118] aaaaaaaaaaaaaaaaaa --- .../practicum/filmorate/model/Film.java | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java index 034e5de..df78ac8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -2,8 +2,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.*; import jdk.jfr.Description; import lombok.AllArgsConstructor; import lombok.Builder; @@ -19,17 +18,32 @@ @AllArgsConstructor(staticName = "of") public class Film { private Long id; - @NotNull - @NotBlank + + @NotNull(message = "Название не может быть null") + @NotBlank(message = "Название не может быть пустым") + @Size(max = 100, message = "Название не может быть длиннее 100 символов") private String name; + @Description("New film update description") + @Size(max = 200, message = "Максимальная длина описания — 200 символов") private String description; + + @NotNull(message = "Дата релиза не может быть null") @JsonFormat(pattern = "yyyy-MM-dd") + @PastOrPresent(message = "Дата релиза должна быть не раньше 28 декабря 1895 года") private LocalDate releaseDate; - @NotNull + + @NotNull(message = "Продолжительность не может быть null") + @Positive(message = "Продолжительность фильма должна быть положительным числом") private Integer duration; + @JsonIgnore private Set likedUsers; + + @NotNull(message = "Рейтинг MPA не может быть null") + @Min(value = 1, message = "Рейтинг MPA должен быть не меньше 1") + @Max(value = 5, message = "Рейтинг MPA должен быть не больше 5") private Long mpa; + private LinkedHashSet genres; } \ No newline at end of file From c85e045432f2ffa21d7ef51b58a8611d2eeb12cb Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 16:01:21 +0500 Subject: [PATCH 024/118] =?UTF-8?q?132=20=D0=BF=D0=BE=D0=BF=D1=8B=D1=82?= =?UTF-8?q?=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 131 ++++++++++++++++-- .../exception/GlobalExceptionHandler.java | 6 + .../filmorate/storage/film/FilmDbStorage.java | 12 +- .../filmorate/FilmDbStorageTest.java | 105 ++++++++++++++ 4 files changed, 240 insertions(+), 14 deletions(-) create mode 100644 src/test/java/ru/yandex/practicum/filmorate/FilmDbStorageTest.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index f6c868f..ba327ff 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -52,38 +52,153 @@ public FilmRequest findById(@PathVariable("id") Long id) throws ConditionsNotMet @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmRequest create(@Valid @RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NullPointerException { + public FilmRequest create(@RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NullPointerException { + // Проверка названия фильма String name = objectNode.get("name").asText(); + if (name == null || name.isBlank()) { + throw new ConditionsNotMetException("Название не может быть пустым"); + } + + // Проверка описания фильма String description = objectNode.get("description").asText(); - String releaseDate = objectNode.get("releaseDate").asText(); + if (description != null && description.length() > 200) { + throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); + } + + // Проверка даты выпуска + String releaseDateStr = objectNode.get("releaseDate").asText(); + LocalDate releaseDate; + try { + releaseDate = LocalDate.parse(releaseDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } catch (Exception e) { + throw new ConditionsNotMetException("Неверный формат даты выпуска. Используйте формат 'yyyy-MM-dd'"); + } + if (releaseDate.isBefore(LocalDate.of(1895, 12, 28))) { + throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); + } + + // Проверка продолжительности Integer duration = objectNode.get("duration").asInt(); + if (duration == null || duration <= 0) { + throw new ConditionsNotMetException("Продолжительность должна быть положительным числом"); + } + + // Проверка MPA List mpa = objectNode.get("mpa").findValuesAsText("id"); + if (mpa == null || mpa.isEmpty()) { + throw new ConditionsNotMetException("Рейтинг MPA должен быть указан"); + } + Long mpaId = Long.valueOf(mpa.get(0).toString()); + if (mpaId < 1 || mpaId > 5) { + throw new ConditionsNotMetException("Некорректный рейтинг MPA"); + } + + // Проверка жанров List genres = new ArrayList<>(); try { genres = objectNode.get("genres").findValuesAsText("id"); } catch (NullPointerException e) { genres = List.of("нет жанра"); - } finally { - return filmStorage.create(Buffer.of(Long.valueOf(0), name, description, LocalDate.parse(releaseDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")), duration, genres, Long.valueOf(mpa.get(0).toString()))); } + for (String genre : genres) { + try { + Long genreId = Long.parseLong(genre); + if (genreId < 1 || genreId > 6) { + throw new ConditionsNotMetException("Некорректный жанр: " + genreId); + } + } catch (NumberFormatException ex) { + throw new ConditionsNotMetException("Неверный формат жанра: " + genre); + } + } + + // Создание фильма + return filmStorage.create(Buffer.of( + Long.valueOf(0), + name, + description, + releaseDate, + duration, + genres, + mpaId + )); } @PutMapping - public FilmRequest update(@Valid @RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NotFoundException { + public FilmRequest update(@RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NotFoundException { + // Проверка ID фильма Long id = objectNode.get("id").asLong(); + if (id == null || id <= 0) { + throw new ConditionsNotMetException("ID фильма должен быть положительным числом"); + } + + // Проверка названия фильма String name = objectNode.get("name").asText(); + if (name == null || name.isBlank()) { + throw new ConditionsNotMetException("Название не может быть пустым"); + } + + // Проверка описания фильма String description = objectNode.get("description").asText(); - String releaseDate = objectNode.get("releaseDate").asText(); + if (description != null && description.length() > 200) { + throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); + } + + // Проверка даты выпуска + String releaseDateStr = objectNode.get("releaseDate").asText(); + LocalDate releaseDate; + try { + releaseDate = LocalDate.parse(releaseDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } catch (Exception e) { + throw new ConditionsNotMetException("Неверный формат даты выпуска. Используйте формат 'yyyy-MM-dd'"); + } + if (releaseDate.isBefore(LocalDate.of(1895, 12, 28))) { + throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); + } + + // Проверка продолжительности Integer duration = objectNode.get("duration").asInt(); + if (duration == null || duration <= 0) { + throw new ConditionsNotMetException("Продолжительность должна быть положительным числом"); + } + + // Проверка MPA List mpa = objectNode.get("mpa").findValuesAsText("id"); + if (mpa == null || mpa.isEmpty()) { + throw new ConditionsNotMetException("Рейтинг MPA должен быть указан"); + } + Long mpaId = Long.valueOf(mpa.get(0).toString()); + if (mpaId < 1 || mpaId > 5) { + throw new ConditionsNotMetException("Некорректный рейтинг MPA"); + } + + // Проверка жанров List genres = new ArrayList<>(); try { genres = objectNode.get("genres").findValuesAsText("id"); } catch (NullPointerException e) { genres = List.of("нет жанра"); - } finally { - return filmStorage.update(Buffer.of(id, name, description, LocalDate.parse(releaseDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")), duration, genres, Long.valueOf(mpa.get(0).toString()))); } + for (String genre : genres) { + try { + Long genreId = Long.parseLong(genre); + if (genreId < 1 || genreId > 6) { + throw new ConditionsNotMetException("Некорректный жанр: " + genreId); + } + } catch (NumberFormatException ex) { + throw new ConditionsNotMetException("Неверный формат жанра: " + genre); + } + } + + // Обновление фильма + return filmStorage.update(Buffer.of( + id, + name, + description, + releaseDate, + duration, + genres, + mpaId + )); } @PutMapping("/{id}/like/{userId}") diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java b/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java index 285b907..69a81a0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java @@ -19,4 +19,10 @@ public ResponseEntity> handleConditionsNotMetException(Condi public ResponseEntity> handleNotFoundException(NotFoundException ex) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of("error", ex.getMessage())); } + + @ExceptionHandler(RuntimeException.class) + public ResponseEntity> handleRuntimeException(RuntimeException ex) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(Map.of("error", "Internal server error: " + ex.getMessage())); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 9e2a80d..76c8997 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -150,31 +150,31 @@ public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException // Проверка названия фильма if (buffer.getName() == null || buffer.getName().isBlank()) { - log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); + log.error("Название не может быть пустым"); throw new ConditionsNotMetException("Название не может быть пустым"); } // Проверка описания фильма if (buffer.getDescription() == null || buffer.getDescription().length() > 200) { - log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); + log.error("Максимальная длина описания — 200 символов"); throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); } // Проверка даты выпуска if (buffer.getReleaseDate() == null || buffer.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { - log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); + log.error("Дата релиза — не раньше 28 декабря 1895 года"); throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); } // Проверка продолжительности фильма if (buffer.getDuration() == null || buffer.getDuration() <= 0) { - log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); + log.error("Продолжительность фильма должна быть положительным числом"); throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); } // Проверка рейтинга MPA if (buffer.getMpa() == null || buffer.getMpa() < 1 || buffer.getMpa() > 5) { - log.error("Exception", new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг")); + log.error("Некорректный рейтинг: {}", buffer.getMpa()); throw new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг"); } @@ -191,7 +191,7 @@ public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException genres = buffer.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); for (Long g : genres) { if (g < 1 || g > 6) { - log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); + log.error("Некорректный жанр: {}", g); throw new NotFoundException(g.toString(), "Некорректный жанр"); } } diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/FilmDbStorageTest.java new file mode 100644 index 0000000..32fff06 --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/FilmDbStorageTest.java @@ -0,0 +1,105 @@ +package ru.yandex.practicum.filmorate; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.jdbc.core.JdbcTemplate; +import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Buffer; +import ru.yandex.practicum.filmorate.storage.film.FilmDbStorage; + +import java.time.LocalDate; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +class FilmDbStorageTest { + + @Mock + private JdbcTemplate jdbcTemplate; + + private FilmDbStorage filmDbStorage; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + filmDbStorage = new FilmDbStorage(jdbcTemplate); + } + + @Test + void createFilmWithEmptyNameShouldThrowException() { + Buffer buffer = Buffer.of( + null, // id + "", // Пустое название + "Valid description", + LocalDate.of(2000, 1, 1), + 120, + Collections.singletonList("1"), + 1L + ); + + assertThrows(ConditionsNotMetException.class, () -> filmDbStorage.create(buffer)); + } + + @Test + void createFilmWithLongDescriptionShouldThrowException() { + Buffer buffer = Buffer.of( + null, // id + "Valid Name", + "A".repeat(201), // Описание длиннее 200 символов + LocalDate.of(2000, 1, 1), + 120, + Collections.singletonList("1"), + 1L + ); + + + assertThrows(ConditionsNotMetException.class, () -> filmDbStorage.create(buffer)); + } + + @Test + void createFilmWithInvalidReleaseDateShouldThrowException() { + Buffer buffer = Buffer.of( + null, // id + "Valid Name", + "Valid description", + LocalDate.of(1890, 1, 1), // Дата раньше 28 декабря 1895 года + 120, + Collections.singletonList("1"), + 1L + ); + assertThrows(ConditionsNotMetException.class, () -> filmDbStorage.create(buffer)); + } + + @Test + void createFilmWithNegativeDurationShouldThrowException() { + Buffer buffer = Buffer.of( + null, // id + "Valid Name", + "Valid description", + LocalDate.of(2000, 1, 1), + -120, // Отрицательная продолжительность + Collections.singletonList("1"), + 1L + ); + + assertThrows(ConditionsNotMetException.class, () -> filmDbStorage.create(buffer)); + } + + @Test + void createFilmWithInvalidMpaShouldThrowException() { + Buffer buffer = Buffer.of( + null, // id + "Valid Name", + "Valid description", + LocalDate.of(2000, 1, 1), + 120, + Collections.singletonList("1"), + 0L // Некорректный рейтинг MPA + ); + + assertThrows(NotFoundException.class, () -> filmDbStorage.create(buffer)); + } +} \ No newline at end of file From 943350ecca8289bccb7431420ebb905cab8afce1 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 16:04:38 +0500 Subject: [PATCH 025/118] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D1=82=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 131 ++---------------- .../exception/GlobalExceptionHandler.java | 8 +- 2 files changed, 9 insertions(+), 130 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index ba327ff..f6c868f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -52,153 +52,38 @@ public FilmRequest findById(@PathVariable("id") Long id) throws ConditionsNotMet @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmRequest create(@RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NullPointerException { - // Проверка названия фильма + public FilmRequest create(@Valid @RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NullPointerException { String name = objectNode.get("name").asText(); - if (name == null || name.isBlank()) { - throw new ConditionsNotMetException("Название не может быть пустым"); - } - - // Проверка описания фильма String description = objectNode.get("description").asText(); - if (description != null && description.length() > 200) { - throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); - } - - // Проверка даты выпуска - String releaseDateStr = objectNode.get("releaseDate").asText(); - LocalDate releaseDate; - try { - releaseDate = LocalDate.parse(releaseDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); - } catch (Exception e) { - throw new ConditionsNotMetException("Неверный формат даты выпуска. Используйте формат 'yyyy-MM-dd'"); - } - if (releaseDate.isBefore(LocalDate.of(1895, 12, 28))) { - throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); - } - - // Проверка продолжительности + String releaseDate = objectNode.get("releaseDate").asText(); Integer duration = objectNode.get("duration").asInt(); - if (duration == null || duration <= 0) { - throw new ConditionsNotMetException("Продолжительность должна быть положительным числом"); - } - - // Проверка MPA List mpa = objectNode.get("mpa").findValuesAsText("id"); - if (mpa == null || mpa.isEmpty()) { - throw new ConditionsNotMetException("Рейтинг MPA должен быть указан"); - } - Long mpaId = Long.valueOf(mpa.get(0).toString()); - if (mpaId < 1 || mpaId > 5) { - throw new ConditionsNotMetException("Некорректный рейтинг MPA"); - } - - // Проверка жанров List genres = new ArrayList<>(); try { genres = objectNode.get("genres").findValuesAsText("id"); } catch (NullPointerException e) { genres = List.of("нет жанра"); + } finally { + return filmStorage.create(Buffer.of(Long.valueOf(0), name, description, LocalDate.parse(releaseDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")), duration, genres, Long.valueOf(mpa.get(0).toString()))); } - for (String genre : genres) { - try { - Long genreId = Long.parseLong(genre); - if (genreId < 1 || genreId > 6) { - throw new ConditionsNotMetException("Некорректный жанр: " + genreId); - } - } catch (NumberFormatException ex) { - throw new ConditionsNotMetException("Неверный формат жанра: " + genre); - } - } - - // Создание фильма - return filmStorage.create(Buffer.of( - Long.valueOf(0), - name, - description, - releaseDate, - duration, - genres, - mpaId - )); } @PutMapping - public FilmRequest update(@RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NotFoundException { - // Проверка ID фильма + public FilmRequest update(@Valid @RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NotFoundException { Long id = objectNode.get("id").asLong(); - if (id == null || id <= 0) { - throw new ConditionsNotMetException("ID фильма должен быть положительным числом"); - } - - // Проверка названия фильма String name = objectNode.get("name").asText(); - if (name == null || name.isBlank()) { - throw new ConditionsNotMetException("Название не может быть пустым"); - } - - // Проверка описания фильма String description = objectNode.get("description").asText(); - if (description != null && description.length() > 200) { - throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); - } - - // Проверка даты выпуска - String releaseDateStr = objectNode.get("releaseDate").asText(); - LocalDate releaseDate; - try { - releaseDate = LocalDate.parse(releaseDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); - } catch (Exception e) { - throw new ConditionsNotMetException("Неверный формат даты выпуска. Используйте формат 'yyyy-MM-dd'"); - } - if (releaseDate.isBefore(LocalDate.of(1895, 12, 28))) { - throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); - } - - // Проверка продолжительности + String releaseDate = objectNode.get("releaseDate").asText(); Integer duration = objectNode.get("duration").asInt(); - if (duration == null || duration <= 0) { - throw new ConditionsNotMetException("Продолжительность должна быть положительным числом"); - } - - // Проверка MPA List mpa = objectNode.get("mpa").findValuesAsText("id"); - if (mpa == null || mpa.isEmpty()) { - throw new ConditionsNotMetException("Рейтинг MPA должен быть указан"); - } - Long mpaId = Long.valueOf(mpa.get(0).toString()); - if (mpaId < 1 || mpaId > 5) { - throw new ConditionsNotMetException("Некорректный рейтинг MPA"); - } - - // Проверка жанров List genres = new ArrayList<>(); try { genres = objectNode.get("genres").findValuesAsText("id"); } catch (NullPointerException e) { genres = List.of("нет жанра"); + } finally { + return filmStorage.update(Buffer.of(id, name, description, LocalDate.parse(releaseDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")), duration, genres, Long.valueOf(mpa.get(0).toString()))); } - for (String genre : genres) { - try { - Long genreId = Long.parseLong(genre); - if (genreId < 1 || genreId > 6) { - throw new ConditionsNotMetException("Некорректный жанр: " + genreId); - } - } catch (NumberFormatException ex) { - throw new ConditionsNotMetException("Неверный формат жанра: " + genre); - } - } - - // Обновление фильма - return filmStorage.update(Buffer.of( - id, - name, - description, - releaseDate, - duration, - genres, - mpaId - )); } @PutMapping("/{id}/like/{userId}") diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java b/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java index 69a81a0..6b55470 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java @@ -19,10 +19,4 @@ public ResponseEntity> handleConditionsNotMetException(Condi public ResponseEntity> handleNotFoundException(NotFoundException ex) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of("error", ex.getMessage())); } - - @ExceptionHandler(RuntimeException.class) - public ResponseEntity> handleRuntimeException(RuntimeException ex) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .body(Map.of("error", "Internal server error: " + ex.getMessage())); - } -} +} \ No newline at end of file From bf5baf95efd2577eecc1c3439e5c9c48c0ab05ff Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 16:17:04 +0500 Subject: [PATCH 026/118] =?UTF-8?q?=D0=B2=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 76c8997..f2e5c45 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -179,34 +179,38 @@ public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException } // Создание фильма - List genres; - LinkedHashSet genres1 = new LinkedHashSet<>(); - SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); - Long f = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); - Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + try { + List genres; + LinkedHashSet genres1 = new LinkedHashSet<>(); + SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); + Long f = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); + Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); - // Проверка и добавление жанров - if (!buffer.getGenres().equals(List.of("нет жанра"))) { - genres = buffer.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); - for (Long g : genres) { - if (g < 1 || g > 6) { - log.error("Некорректный жанр: {}", g); - throw new NotFoundException(g.toString(), "Некорректный жанр"); + // Проверка и добавление жанров + if (!buffer.getGenres().equals(List.of("нет жанра"))) { + genres = buffer.getGenres().stream().map(Long::parseLong).toList(); + for (Long g : genres) { + if (g < 1 || g > 6) { + log.error("Некорректный жанр: {}", g); + throw new NotFoundException(g.toString(), "Некорректный жанр"); + } + } + for (Long g : genres) { + jdbcTemplate.update(sqlQuery12, f, g); + genres1.add(Genre.of(g, genre.get(g))); } } - for (Long g : genres) { - jdbcTemplate.update(sqlQuery12, f, g); - genres1.add(Genre.of(g, genre.get(g))); - } - } - // Обновление рейтинга MPA - jdbcTemplate.update(sqlQuery14, buffer.getMpa(), f); + // Обновление рейтинга MPA + jdbcTemplate.update(sqlQuery14, buffer.getMpa(), f); - // Создание объекта FilmRequest - FilmRequest film = FilmRequest.of(f, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres1); - return film; + // Создание объекта FilmRequest + return FilmRequest.of(f, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres1); + } catch (DataAccessException e) { + log.error("Ошибка при работе с базой данных", e); + throw new ConditionsNotMetException("Ошибка при работе с базой данных"); + } } public FilmRequest update(@Valid Buffer newFilm) throws ConditionsNotMetException, NotFoundException { From 4725a474f6a88c8ee4d7877ee8ae88205d51ac09 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 16:30:04 +0500 Subject: [PATCH 027/118] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=D0=B0=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B=20update=20?= =?UTF-8?q?create?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 233 ++++++++---------- 1 file changed, 102 insertions(+), 131 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index f2e5c45..fd6339c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -19,7 +19,8 @@ import java.sql.ResultSet; import java.sql.SQLException; -import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.chrono.ChronoLocalDate; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; @@ -145,151 +146,121 @@ public FilmRequest findById(Long id) throws ConditionsNotMetException, NotFoundE } } + @Override public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException, NullPointerException { log.info("Обработка Create-запроса..."); - - // Проверка названия фильма - if (buffer.getName() == null || buffer.getName().isBlank()) { - log.error("Название не может быть пустым"); - throw new ConditionsNotMetException("Название не может быть пустым"); - } - - // Проверка описания фильма - if (buffer.getDescription() == null || buffer.getDescription().length() > 200) { - log.error("Максимальная длина описания — 200 символов"); - throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); - } - - // Проверка даты выпуска - if (buffer.getReleaseDate() == null || buffer.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { - log.error("Дата релиза — не раньше 28 декабря 1895 года"); - throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); - } - - // Проверка продолжительности фильма - if (buffer.getDuration() == null || buffer.getDuration() <= 0) { - log.error("Продолжительность фильма должна быть положительным числом"); - throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); - } - - // Проверка рейтинга MPA - if (buffer.getMpa() == null || buffer.getMpa() < 1 || buffer.getMpa() > 5) { - log.error("Некорректный рейтинг: {}", buffer.getMpa()); - throw new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг"); - } - - // Создание фильма - try { - List genres; - LinkedHashSet genres1 = new LinkedHashSet<>(); - SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); - Long f = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); - Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); - - // Проверка и добавление жанров - if (!buffer.getGenres().equals(List.of("нет жанра"))) { - genres = buffer.getGenres().stream().map(Long::parseLong).toList(); - for (Long g : genres) { - if (g < 1 || g > 6) { - log.error("Некорректный жанр: {}", g); - throw new NotFoundException(g.toString(), "Некорректный жанр"); + if (buffer.getName() != null && !buffer.getName().isBlank() && !buffer.getName().equals("")) { + if (buffer.getDescription().length() > 200) { + log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); + throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); + } else if (buffer.getReleaseDate().isBefore(ChronoLocalDate.from(LocalDateTime.of(1895, 12, 28, 0, 0, 0)))) { + log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); + throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); + } else if (buffer.getDuration() != null && buffer.getDuration() != 0) { + if (buffer.getDuration() < 0) { + log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); + throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); + } else if (!(buffer.getMpa() > 0 && buffer.getMpa() < 6)) { + log.error("Exception", new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг")); + throw new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг"); + } else { + List genres; + LinkedHashSet genres1 = new LinkedHashSet<>(); + String sqlQuery; + SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); + Long f = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); + Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + if (!buffer.getGenres().equals(List.of("нет жанра"))) { + genres = buffer.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); + for (Long g : genres) { + if (!(g > 0 && g < 7)) { + log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); + throw new NotFoundException(g.toString(), "Некорректный жанр"); + } + } + for (Long g : genres) { + jdbcTemplate.update(sqlQuery12, f, g); + genres1.add(Genre.of(g, genre.get(g))); + } } + jdbcTemplate.update(sqlQuery14, buffer.getMpa(), f); + + FilmRequest film = FilmRequest.of(f, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres1); + return film; } - for (Long g : genres) { - jdbcTemplate.update(sqlQuery12, f, g); - genres1.add(Genre.of(g, genre.get(g))); - } + } else { + log.error("Exception", new NullPointerException("Продолжительность фильма не может быть нулевой")); + throw new NullPointerException("Продолжительность фильма не может быть нулевой"); } - - // Обновление рейтинга MPA - jdbcTemplate.update(sqlQuery14, buffer.getMpa(), f); - - // Создание объекта FilmRequest - return FilmRequest.of(f, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres1); - } catch (DataAccessException e) { - log.error("Ошибка при работе с базой данных", e); - throw new ConditionsNotMetException("Ошибка при работе с базой данных"); + } else { + log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); + throw new ConditionsNotMetException("Название не может быть пустым"); } } + @Override public FilmRequest update(@Valid Buffer newFilm) throws ConditionsNotMetException, NotFoundException { log.info("Обработка Put-запроса..."); - - // Проверка ID фильма if (newFilm.getId() == null) { log.error("Exception", new ConditionsNotMetException("Id должен быть указан")); throw new ConditionsNotMetException("Id должен быть указан"); - } - - // Проверка названия фильма - if (newFilm.getName() == null || newFilm.getName().isBlank()) { - log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); - throw new ConditionsNotMetException("Название не может быть пустым"); - } - - // Проверка описания фильма - if (newFilm.getDescription() == null || newFilm.getDescription().length() > 200) { - log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); - throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); - } - - // Проверка даты выпуска - if (newFilm.getReleaseDate() == null || newFilm.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { - log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); - throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); - } - - // Проверка продолжительности фильма - if (newFilm.getDuration() == null || newFilm.getDuration() <= 0) { - log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); - throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); - } - - // Проверка рейтинга MPA - if (newFilm.getMpa() == null || newFilm.getMpa() < 1 || newFilm.getMpa() > 5) { - log.error("Exception", new NotFoundException(newFilm.getMpa().toString(), "Некорректный рейтинг")); - throw new NotFoundException(newFilm.getMpa().toString(), "Некорректный рейтинг"); - } - - // Получение старого фильма - FilmRequest oldFilm = findById(newFilm.getId()); - - // Обновление данных фильма - oldFilm.setName(newFilm.getName()); - oldFilm.setDescription(newFilm.getDescription()); - oldFilm.setReleaseDate(newFilm.getReleaseDate()); - oldFilm.setDuration(newFilm.getDuration()); - - // Обновление жанров - LinkedHashSet genres1 = new LinkedHashSet<>(); - Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); - - if (!newFilm.getGenres().equals(List.of("нет жанра"))) { - List genres = newFilm.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); - for (Long g : genres) { - if (g < 1 || g > 6) { - log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); - throw new NotFoundException(g.toString(), "Некорректный жанр"); + } else { + FilmRequest oldFilm = findById(newFilm.getId()); + if (newFilm.getName() != null && !newFilm.getName().isBlank()) { + oldFilm.setName(newFilm.getName()); + if (newFilm.getDescription().length() > 200) { + log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); + throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); + } else { + oldFilm.setDescription(newFilm.getDescription()); + if (newFilm.getReleaseDate().isBefore(ChronoLocalDate.from(LocalDateTime.of(1895, 12, 28, 0, 0, 0)))) { + log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); + throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); + } else { + oldFilm.setReleaseDate(newFilm.getReleaseDate()); + if (newFilm.getDuration() != null && newFilm.getDuration() != 0) { + if (newFilm.getDuration() < 0) { + log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); + throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); + } else { + oldFilm.setDuration(newFilm.getDuration()); + if (!(newFilm.getMpa() > 0 && newFilm.getMpa() < 6)) { + log.error("Exception", new NotFoundException(newFilm.getMpa().toString(), "Некорректный рейтинг")); + throw new NotFoundException(newFilm.getMpa().toString(), "Некорректный рейтинг"); + } + LinkedHashSet genres1 = new LinkedHashSet<>(); + Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + if (!newFilm.getGenres().equals(List.of("нет жанра"))) { + List genres = newFilm.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); + for (Long g : genres) { + if (!(g > 0 && g < 7)) { + log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); + throw new NotFoundException(g.toString(), "Некорректный жанр"); + } + } + jdbcTemplate.update(sqlQuery11, oldFilm.getId()); + for (Long g : genres) { + jdbcTemplate.update(sqlQuery12, oldFilm.getId(), g); + genres1.add(Genre.of(g, genre.get(g))); + } + } + if (!oldFilm.getMpa().equals(newFilm.getMpa()) && newFilm.getMpa() > 0 && newFilm.getMpa() < 6) + oldFilm.setMpa(Mpa.of(newFilm.getMpa(), rating.get(newFilm.getMpa()))); + jdbcTemplate.update(sqlQuery13, oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), oldFilm.getMpa().getId(), oldFilm.getId()); + return FilmRequest.of(oldFilm.getId(), oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), new HashSet<>(), oldFilm.getMpa(), genres1); + } + } else { + log.error("Exception", new NullPointerException("Продолжительность фильма не может быть нулевой")); + throw new NullPointerException("Продолжительность фильма не может быть нулевой"); + } + } } + } else { + log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); + throw new ConditionsNotMetException("Название не может быть пустым"); } - jdbcTemplate.update(sqlQuery11, oldFilm.getId()); - for (Long g : genres) { - jdbcTemplate.update(sqlQuery12, oldFilm.getId(), g); - genres1.add(Genre.of(g, genre.get(g))); - } - } - - // Обновление рейтинга MPA - if (!oldFilm.getMpa().equals(newFilm.getMpa())) { - oldFilm.setMpa(Mpa.of(newFilm.getMpa(), rating.get(newFilm.getMpa()))); } - - // Обновление фильма в базе данных - jdbcTemplate.update(sqlQuery13, oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), oldFilm.getMpa().getId(), oldFilm.getId()); - - // Возврат обновленного фильма - return FilmRequest.of(oldFilm.getId(), oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), new HashSet<>(), oldFilm.getMpa(), genres1); } } \ No newline at end of file From 546be13ab78ff0f5324a5e7e6332494997ea03c3 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 17:15:52 +0500 Subject: [PATCH 028/118] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=D0=B0=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/ConditionsNotMetException.java | 13 ++++------- .../exception/GlobalExceptionHandler.java | 22 ------------------- .../filmorate/storage/film/FilmDbStorage.java | 3 ++- 3 files changed, 6 insertions(+), 32 deletions(-) delete mode 100644 src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ConditionsNotMetException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ConditionsNotMetException.java index 8972e35..d84fada 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/ConditionsNotMetException.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ConditionsNotMetException.java @@ -1,14 +1,9 @@ package ru.yandex.practicum.filmorate.exception; -public class ConditionsNotMetException extends RuntimeException { - - private final String id; // Идентификатор, связанный с ошибкой +import java.util.Objects; - public ConditionsNotMetException(String id) { - this.id = id; - } - - public String getId() { - return id; +public class ConditionsNotMetException extends RuntimeException { + public ConditionsNotMetException(String message) { + super(Objects.requireNonNull(message, "Сообщение об ошибке не может быть null")); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java b/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java deleted file mode 100644 index 6b55470..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/GlobalExceptionHandler.java +++ /dev/null @@ -1,22 +0,0 @@ -package ru.yandex.practicum.filmorate.exception; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; - -import java.util.Map; - -@ControllerAdvice -public class GlobalExceptionHandler { - - @ExceptionHandler(ConditionsNotMetException.class) - public ResponseEntity> handleConditionsNotMetException(ConditionsNotMetException ex) { - return ResponseEntity.badRequest().body(Map.of("error", ex.getMessage())); - } - - @ExceptionHandler(NotFoundException.class) - public ResponseEntity> handleNotFoundException(NotFoundException ex) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of("error", ex.getMessage())); - } -} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index fd6339c..76815ff 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -19,6 +19,7 @@ import java.sql.ResultSet; import java.sql.SQLException; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.chrono.ChronoLocalDate; import java.time.format.DateTimeFormatter; @@ -153,7 +154,7 @@ public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException if (buffer.getDescription().length() > 200) { log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); - } else if (buffer.getReleaseDate().isBefore(ChronoLocalDate.from(LocalDateTime.of(1895, 12, 28, 0, 0, 0)))) { + } else if (buffer.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); } else if (buffer.getDuration() != null && buffer.getDuration() != 0) { From 801d655e843cf0ec63969f8cfadfefea9e609978 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 17:33:49 +0500 Subject: [PATCH 029/118] =?UTF-8?q?=D1=80=D0=B5=D1=84=D1=80=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BA=D0=BB=D0=B0=D1=81?= =?UTF-8?q?=D1=81=D0=B0=20filmdbstorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 277 +++++++++--------- 1 file changed, 132 insertions(+), 145 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 76815ff..0ed289e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -20,11 +20,8 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.chrono.ChronoLocalDate; import java.time.format.DateTimeFormatter; import java.util.*; -import java.util.stream.Collectors; @Repository @RequiredArgsConstructor @@ -38,23 +35,17 @@ public class FilmDbStorage implements FilmStorage { private final JdbcTemplate jdbcTemplate; private FilmInterface filmInterface; - private final String sqlQuery1 = "select id, name, description, releaseDate, duration from film"; - private final String sqlQuery2 = "select filmId, userId from likedUsers"; - private final String sqlQuery3 = "select filmId, genreId from filmGenre"; - private final String sqlQuery4 = "select id, ratingId from film"; - private final String sqlQuery5 = "select id, name, description, releaseDate, duration from film where id = ?"; - private final String sqlQuery6 = "select filmId, userId from likedUsers where filmId = ?"; - private final String sqlQuery7 = "select filmId, genreId from filmGenre where filmId = ?"; - private final String sqlQuery8 = "select id, ratingId from film where id = ?"; private final String sqlQuery9 = "select id, name from genre"; private final String sqlQuery10 = "select id, rating from filmrating"; - private final String sqlQuery11 = "delete from filmGenre where filmId = ?"; - private final String sqlQuery12 = "insert into filmGenre(filmId, genreId) " + "values (?, ?)"; - private final String sqlQuery13 = "update film set " + "name = ?, description = ?, releaseDate = ?, duration = ?, ratingId = ? " + "where id = ?"; - private final String sqlQuery14 = "update film set " + "ratingId = ? " + "where id = ?"; private Film mapRowToFilm(ResultSet resultSet, int rowNum) throws SQLException { - return Film.builder().id(resultSet.getLong("id")).name(resultSet.getString("name")).description(resultSet.getString("description")).releaseDate(resultSet.getDate("releaseDate").toLocalDate()).duration(resultSet.getInt("duration")).build(); + return Film.builder() + .id(resultSet.getLong("id")) + .name(resultSet.getString("name")) + .description(resultSet.getString("description")) + .releaseDate(resultSet.getDate("releaseDate").toLocalDate()) + .duration(resultSet.getInt("duration")) + .build(); } public static class LikedUsersExtractor implements ResultSetExtractor>> { @@ -91,7 +82,7 @@ public Map extractData(ResultSet rs) throws SQLException { Map data = new HashMap<>(); while (rs.next()) { Long id = rs.getLong("id"); - data.putIfAbsent(id, Long.valueOf(0)); + data.putIfAbsent(id, 0L); Long ratingId = rs.getLong("ratingId"); data.put(id, ratingId); } @@ -102,13 +93,20 @@ public Map extractData(ResultSet rs) throws SQLException { @Override public List findAll() { log.info("Обработка Get-запроса..."); + String sqlQuery1 = "select id, name, description, releaseDate, duration from film"; List films = jdbcTemplate.query(sqlQuery1, this::mapRowToFilm); + String sqlQuery2 = "select filmId, userId from likedUsers"; Map> likedUsers = jdbcTemplate.query(sqlQuery2, new LikedUsersExtractor()); + String sqlQuery3 = "select filmId, genreId from filmGenre"; Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmGenreExtractor()); + String sqlQuery4 = "select id, ratingId from film"; Map filmRating = jdbcTemplate.query(sqlQuery4, new FilmRatingExtractor()); for (Film film : films) { + assert likedUsers != null; film.setLikedUsers(likedUsers.get(film.getId())); + assert filmGenre != null; film.setGenres(filmGenre.get(film.getId())); + assert filmRating != null; film.setMpa(filmRating.get(film.getId())); } return films; @@ -117,87 +115,60 @@ public List findAll() { @Override public FilmRequest findById(Long id) throws ConditionsNotMetException, NotFoundException { log.info("Обработка Get-запроса..."); - if (id != 0 && !id.equals(null)) { - try { - jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); - } catch (DataAccessException e) { - if (e != null) { - log.error("Exception", new NotFoundException(id.toString(), "Идентификатор фильма отсутствует в базе")); - throw new NotFoundException(id.toString(), "Идентификатор фильма отсутствует в базе"); - } - } - Film film = jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); - Map> likedUsers = jdbcTemplate.query(sqlQuery6, new LikedUsersExtractor(), id); - Map> filmGenre = jdbcTemplate.query(sqlQuery7, new FilmGenreExtractor(), id); - Map filmRating = jdbcTemplate.query(sqlQuery8, new FilmRatingExtractor(), id); - film.setLikedUsers(likedUsers.get(id)); - film.setGenres(filmGenre.get(id)); - Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); - LinkedHashSet genres = new LinkedHashSet<>(); - if (!filmGenre.isEmpty()) { - for (Long g : filmGenre.get(id)) - genres.add(Genre.of(g, genre.get(g))); - } - film.setMpa(filmRating.get(id)); - return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), Mpa.of(film.getMpa(), rating.get(film.getMpa())), genres); - } else { + if (id == null || id == 0) { log.error("Exception", new ConditionsNotMetException("Идентификатор фильма не может быть нулевой")); throw new ConditionsNotMetException("Идентификатор фильма не может быть нулевой"); } + + String sqlQuery5 = "select id, name, description, releaseDate, duration from film where id = ?"; + try { + jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); + } catch (DataAccessException e) { + log.error("Exception", new NotFoundException(id.toString(), "Идентификатор фильма отсутствует в базе")); + throw new NotFoundException(id.toString(), "Идентификатор фильма отсутствует в базе"); + } + + Film film = jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); + String sqlQuery6 = "select filmId, userId from likedUsers where filmId = ?"; + Map> likedUsers = jdbcTemplate.query(sqlQuery6, new LikedUsersExtractor(), id); + String sqlQuery7 = "select filmId, genreId from filmGenre where filmId = ?"; + Map> filmGenre = jdbcTemplate.query(sqlQuery7, new FilmGenreExtractor(), id); + String sqlQuery8 = "select id, ratingId from film where id = ?"; + Map filmRating = jdbcTemplate.query(sqlQuery8, new FilmRatingExtractor(), id); + assert film != null; + assert likedUsers != null; + film.setLikedUsers(likedUsers.get(id)); + assert filmGenre != null; + film.setGenres(filmGenre.get(id)); + Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + LinkedHashSet genres = new LinkedHashSet<>(); + if (!filmGenre.isEmpty()) { + for (Long g : filmGenre.get(id)) { + assert genre != null; + genres.add(Genre.of(g, genre.get(g))); + } + } + assert filmRating != null; + film.setMpa(filmRating.get(id)); + return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), Mpa.of(film.getMpa(), rating.get(film.getMpa())), genres); } @Override public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException, NullPointerException { log.info("Обработка Create-запроса..."); - if (buffer.getName() != null && !buffer.getName().isBlank() && !buffer.getName().equals("")) { - if (buffer.getDescription().length() > 200) { - log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); - throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); - } else if (buffer.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { - log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); - throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); - } else if (buffer.getDuration() != null && buffer.getDuration() != 0) { - if (buffer.getDuration() < 0) { - log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); - throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); - } else if (!(buffer.getMpa() > 0 && buffer.getMpa() < 6)) { - log.error("Exception", new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг")); - throw new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг"); - } else { - List genres; - LinkedHashSet genres1 = new LinkedHashSet<>(); - String sqlQuery; - SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); - Long f = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); - Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); - if (!buffer.getGenres().equals(List.of("нет жанра"))) { - genres = buffer.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); - for (Long g : genres) { - if (!(g > 0 && g < 7)) { - log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); - throw new NotFoundException(g.toString(), "Некорректный жанр"); - } - } - for (Long g : genres) { - jdbcTemplate.update(sqlQuery12, f, g); - genres1.add(Genre.of(g, genre.get(g))); - } - } - jdbcTemplate.update(sqlQuery14, buffer.getMpa(), f); - - FilmRequest film = FilmRequest.of(f, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres1); - return film; - } - } else { - log.error("Exception", new NullPointerException("Продолжительность фильма не может быть нулевой")); - throw new NullPointerException("Продолжительность фильма не может быть нулевой"); - } - } else { - log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); - throw new ConditionsNotMetException("Название не может быть пустым"); - } + validateBuffer(buffer); + + SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); + Long filmId = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); + + Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + + LinkedHashSet genres = processGenres(buffer.getGenres(), filmId, genre); + updateFilmRating(buffer.getMpa(), filmId); + + return FilmRequest.of(filmId, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres); } @Override @@ -206,62 +177,78 @@ public FilmRequest update(@Valid Buffer newFilm) throws ConditionsNotMetExceptio if (newFilm.getId() == null) { log.error("Exception", new ConditionsNotMetException("Id должен быть указан")); throw new ConditionsNotMetException("Id должен быть указан"); - } else { - FilmRequest oldFilm = findById(newFilm.getId()); - if (newFilm.getName() != null && !newFilm.getName().isBlank()) { - oldFilm.setName(newFilm.getName()); - if (newFilm.getDescription().length() > 200) { - log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); - throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); - } else { - oldFilm.setDescription(newFilm.getDescription()); - if (newFilm.getReleaseDate().isBefore(ChronoLocalDate.from(LocalDateTime.of(1895, 12, 28, 0, 0, 0)))) { - log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); - throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); - } else { - oldFilm.setReleaseDate(newFilm.getReleaseDate()); - if (newFilm.getDuration() != null && newFilm.getDuration() != 0) { - if (newFilm.getDuration() < 0) { - log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); - throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); - } else { - oldFilm.setDuration(newFilm.getDuration()); - if (!(newFilm.getMpa() > 0 && newFilm.getMpa() < 6)) { - log.error("Exception", new NotFoundException(newFilm.getMpa().toString(), "Некорректный рейтинг")); - throw new NotFoundException(newFilm.getMpa().toString(), "Некорректный рейтинг"); - } - LinkedHashSet genres1 = new LinkedHashSet<>(); - Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); - if (!newFilm.getGenres().equals(List.of("нет жанра"))) { - List genres = newFilm.getGenres().stream().map(item -> Long.parseLong(item)).collect(Collectors.toList()); - for (Long g : genres) { - if (!(g > 0 && g < 7)) { - log.error("Exception", new NotFoundException(g.toString(), "Некорректный жанр")); - throw new NotFoundException(g.toString(), "Некорректный жанр"); - } - } - jdbcTemplate.update(sqlQuery11, oldFilm.getId()); - for (Long g : genres) { - jdbcTemplate.update(sqlQuery12, oldFilm.getId(), g); - genres1.add(Genre.of(g, genre.get(g))); - } - } - if (!oldFilm.getMpa().equals(newFilm.getMpa()) && newFilm.getMpa() > 0 && newFilm.getMpa() < 6) - oldFilm.setMpa(Mpa.of(newFilm.getMpa(), rating.get(newFilm.getMpa()))); - jdbcTemplate.update(sqlQuery13, oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), oldFilm.getMpa().getId(), oldFilm.getId()); - return FilmRequest.of(oldFilm.getId(), oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), new HashSet<>(), oldFilm.getMpa(), genres1); - } - } else { - log.error("Exception", new NullPointerException("Продолжительность фильма не может быть нулевой")); - throw new NullPointerException("Продолжительность фильма не может быть нулевой"); - } - } - } - } else { - log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); - throw new ConditionsNotMetException("Название не может быть пустым"); + } + + FilmRequest oldFilm = findById(newFilm.getId()); + validateBuffer(newFilm); + + oldFilm.setName(newFilm.getName()); + oldFilm.setDescription(newFilm.getDescription()); + oldFilm.setReleaseDate(newFilm.getReleaseDate()); + oldFilm.setDuration(newFilm.getDuration()); + + Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + + LinkedHashSet genres = processGenres(newFilm.getGenres(), oldFilm.getId(), genre); + updateFilmRating(newFilm.getMpa(), oldFilm.getId()); + + String sqlQuery13 = "update film set name = ?, description = ?, releaseDate = ?, duration = ?, ratingId = ? where id = ?"; + jdbcTemplate.update(sqlQuery13, oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), + oldFilm.getDuration(), oldFilm.getMpa().getId(), oldFilm.getId()); + + return FilmRequest.of(oldFilm.getId(), oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), + oldFilm.getDuration(), new HashSet<>(), Mpa.of(newFilm.getMpa(), rating.get(newFilm.getMpa())), genres); + } + + private void validateBuffer(Buffer buffer) throws ConditionsNotMetException, NullPointerException { + if (buffer.getName() == null || buffer.getName().isBlank()) { + log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); + throw new ConditionsNotMetException("Название не может быть пустым"); + } + + if (buffer.getDescription().length() > 200) { + log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); + throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); + } + + if (buffer.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { + log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); + throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); + } + + if (buffer.getDuration() == null || buffer.getDuration() <= 0) { + log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); + throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); + } + + if (!(buffer.getMpa() > 0 && buffer.getMpa() < 6)) { + log.error("Exception", new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг")); + throw new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг"); + } + } + + private LinkedHashSet processGenres(List genres, Long filmId, Map genreMap) { + LinkedHashSet result = new LinkedHashSet<>(); + if (genres == null || genres.equals(List.of("нет жанра"))) { + return result; + } + + for (String genreIdStr : genres) { + Long genreId = Long.parseLong(genreIdStr); + if (!(genreId > 0 && genreId < 7)) { + log.error("Exception", new NotFoundException(genreId.toString(), "Некорректный жанр")); + throw new NotFoundException(genreId.toString(), "Некорректный жанр"); } + String sqlQuery12 = "insert into filmGenre(filmId, genreId) values (?, ?)"; + jdbcTemplate.update(sqlQuery12, filmId, genreId); + result.add(Genre.of(genreId, genreMap.get(genreId))); } + return result; + } + + private void updateFilmRating(Long mpaId, Long filmId) { + String sqlQuery14 = "update film set ratingId = ? where id = ?"; + jdbcTemplate.update(sqlQuery14, mpaId, filmId); } } \ No newline at end of file From 9977efd39e497df7339d75c36d8a3c3f51ecbc15 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 17:45:41 +0500 Subject: [PATCH 030/118] =?UTF-8?q?=D0=B5=D1=89=D0=B5=20=D1=80=D0=B5=D1=84?= =?UTF-8?q?=D1=80=D0=B0=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 96 +++++---- .../filmorate/storage/film/FilmStorage.java | 8 +- .../storage/film/InMemoryFilmStorage.java | 133 ------------- .../storage/user/InMemoryUserStorage.java | 183 ------------------ 4 files changed, 59 insertions(+), 361 deletions(-) delete mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/film/InMemoryFilmStorage.java delete mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/user/InMemoryUserStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 0ed289e..8bd73dd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -14,13 +14,11 @@ import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.*; -import ru.yandex.practicum.filmorate.service.FilmInterface; import ru.yandex.practicum.filmorate.service.FilmService; import java.sql.ResultSet; import java.sql.SQLException; import java.time.LocalDate; -import java.time.format.DateTimeFormatter; import java.util.*; @Repository @@ -31,12 +29,27 @@ @Qualifier("FilmDbStorage") public class FilmDbStorage implements FilmStorage { - private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - private final JdbcTemplate jdbcTemplate; - private FilmInterface filmInterface; + //SQL-запросы + private static final String SQL_SELECT_GENRES = "select id, name from genre"; + private static final String SQL_SELECT_RATINGS = "select id, rating from filmrating"; + private static final String SQL_INSERT_FILM_GENRE = "insert into filmGenre(filmId, genreId) values (?, ?)"; + private static final String SQL_UPDATE_FILM_RATING = "update film set ratingId = ? where id = ?"; + private static final String SQL_UPDATE_FILM = "update film set name = ?, description = ?, releaseDate = ?, duration = ?, ratingId = ? where id = ?"; + + //сообщения для логирования и исключений + private static final String LOG_GET_REQUEST = "Обработка Get-запроса..."; + private static final String LOG_CREATE_REQUEST = "Обработка Create-запроса..."; + private static final String LOG_UPDATE_REQUEST = "Обработка Put-запроса..."; + private static final String ERROR_NULL_ID = "Идентификатор фильма не может быть нулевой"; + private static final String ERROR_FILM_NOT_FOUND = "Идентификатор фильма отсутствует в базе"; + private static final String ERROR_EMPTY_NAME = "Название не может быть пустым"; + private static final String ERROR_DESCRIPTION_LENGTH = "Максимальная длина описания — 200 символов"; + private static final String ERROR_RELEASE_DATE = "Дата релиза — не раньше 28 декабря 1895 года"; + private static final String ERROR_DURATION = "Продолжительность фильма должна быть положительным числом"; + private static final String ERROR_INVALID_RATING = "Некорректный рейтинг"; + private static final String ERROR_INVALID_GENRE = "Некорректный жанр"; - private final String sqlQuery9 = "select id, name from genre"; - private final String sqlQuery10 = "select id, rating from filmrating"; + private final JdbcTemplate jdbcTemplate; private Film mapRowToFilm(ResultSet resultSet, int rowNum) throws SQLException { return Film.builder() @@ -92,7 +105,7 @@ public Map extractData(ResultSet rs) throws SQLException { @Override public List findAll() { - log.info("Обработка Get-запроса..."); + log.info(LOG_GET_REQUEST); String sqlQuery1 = "select id, name, description, releaseDate, duration from film"; List films = jdbcTemplate.query(sqlQuery1, this::mapRowToFilm); String sqlQuery2 = "select filmId, userId from likedUsers"; @@ -114,18 +127,17 @@ public List findAll() { @Override public FilmRequest findById(Long id) throws ConditionsNotMetException, NotFoundException { - log.info("Обработка Get-запроса..."); + log.info(LOG_GET_REQUEST); if (id == null || id == 0) { - log.error("Exception", new ConditionsNotMetException("Идентификатор фильма не может быть нулевой")); - throw new ConditionsNotMetException("Идентификатор фильма не может быть нулевой"); + logAndThrowConditionsNotMetException(ERROR_NULL_ID); } String sqlQuery5 = "select id, name, description, releaseDate, duration from film where id = ?"; try { jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); } catch (DataAccessException e) { - log.error("Exception", new NotFoundException(id.toString(), "Идентификатор фильма отсутствует в базе")); - throw new NotFoundException(id.toString(), "Идентификатор фильма отсутствует в базе"); + assert id != null; + logAndThrowNotFoundException(id.toString(), ERROR_FILM_NOT_FOUND); } Film film = jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); @@ -140,8 +152,8 @@ public FilmRequest findById(Long id) throws ConditionsNotMetException, NotFoundE film.setLikedUsers(likedUsers.get(id)); assert filmGenre != null; film.setGenres(filmGenre.get(id)); - Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new FilmService.RatingNameExtractor()); LinkedHashSet genres = new LinkedHashSet<>(); if (!filmGenre.isEmpty()) { for (Long g : filmGenre.get(id)) { @@ -151,19 +163,20 @@ public FilmRequest findById(Long id) throws ConditionsNotMetException, NotFoundE } assert filmRating != null; film.setMpa(filmRating.get(id)); + assert rating != null; return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), Mpa.of(film.getMpa(), rating.get(film.getMpa())), genres); } @Override public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException, NullPointerException { - log.info("Обработка Create-запроса..."); + log.info(LOG_CREATE_REQUEST); validateBuffer(buffer); SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); Long filmId = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); - Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new FilmService.RatingNameExtractor()); LinkedHashSet genres = processGenres(buffer.getGenres(), filmId, genre); updateFilmRating(buffer.getMpa(), filmId); @@ -173,10 +186,9 @@ public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException @Override public FilmRequest update(@Valid Buffer newFilm) throws ConditionsNotMetException, NotFoundException { - log.info("Обработка Put-запроса..."); + log.info(LOG_UPDATE_REQUEST); if (newFilm.getId() == null) { - log.error("Exception", new ConditionsNotMetException("Id должен быть указан")); - throw new ConditionsNotMetException("Id должен быть указан"); + logAndThrowConditionsNotMetException("Id должен быть указан"); } FilmRequest oldFilm = findById(newFilm.getId()); @@ -187,44 +199,39 @@ public FilmRequest update(@Valid Buffer newFilm) throws ConditionsNotMetExceptio oldFilm.setReleaseDate(newFilm.getReleaseDate()); oldFilm.setDuration(newFilm.getDuration()); - Map genre = jdbcTemplate.query(sqlQuery9, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(sqlQuery10, new FilmService.RatingNameExtractor()); + Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new FilmService.GenreExtractor()); + Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new FilmService.RatingNameExtractor()); LinkedHashSet genres = processGenres(newFilm.getGenres(), oldFilm.getId(), genre); updateFilmRating(newFilm.getMpa(), oldFilm.getId()); - String sqlQuery13 = "update film set name = ?, description = ?, releaseDate = ?, duration = ?, ratingId = ? where id = ?"; - jdbcTemplate.update(sqlQuery13, oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), + jdbcTemplate.update(SQL_UPDATE_FILM, oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), oldFilm.getMpa().getId(), oldFilm.getId()); + assert rating != null; return FilmRequest.of(oldFilm.getId(), oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), new HashSet<>(), Mpa.of(newFilm.getMpa(), rating.get(newFilm.getMpa())), genres); } private void validateBuffer(Buffer buffer) throws ConditionsNotMetException, NullPointerException { if (buffer.getName() == null || buffer.getName().isBlank()) { - log.error("Exception", new ConditionsNotMetException("Название не может быть пустым")); - throw new ConditionsNotMetException("Название не может быть пустым"); + logAndThrowConditionsNotMetException(ERROR_EMPTY_NAME); } if (buffer.getDescription().length() > 200) { - log.error("Exception", new ConditionsNotMetException("Максимальная длина описания — 200 символов")); - throw new ConditionsNotMetException("Максимальная длина описания — 200 символов"); + logAndThrowConditionsNotMetException(ERROR_DESCRIPTION_LENGTH); } if (buffer.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { - log.error("Exception", new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года")); - throw new ConditionsNotMetException("Дата релиза — не раньше 28 декабря 1895 года"); + logAndThrowConditionsNotMetException(ERROR_RELEASE_DATE); } if (buffer.getDuration() == null || buffer.getDuration() <= 0) { - log.error("Exception", new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом")); - throw new ConditionsNotMetException("Продолжительность фильма должна быть положительным числом"); + logAndThrowConditionsNotMetException(ERROR_DURATION); } if (!(buffer.getMpa() > 0 && buffer.getMpa() < 6)) { - log.error("Exception", new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг")); - throw new NotFoundException(buffer.getMpa().toString(), "Некорректный рейтинг"); + logAndThrowNotFoundException(buffer.getMpa().toString(), ERROR_INVALID_RATING); } } @@ -237,18 +244,25 @@ private LinkedHashSet processGenres(List genres, Long filmId, Map for (String genreIdStr : genres) { Long genreId = Long.parseLong(genreIdStr); if (!(genreId > 0 && genreId < 7)) { - log.error("Exception", new NotFoundException(genreId.toString(), "Некорректный жанр")); - throw new NotFoundException(genreId.toString(), "Некорректный жанр"); + logAndThrowNotFoundException(genreId.toString(), ERROR_INVALID_GENRE); } - String sqlQuery12 = "insert into filmGenre(filmId, genreId) values (?, ?)"; - jdbcTemplate.update(sqlQuery12, filmId, genreId); + jdbcTemplate.update(SQL_INSERT_FILM_GENRE, filmId, genreId); result.add(Genre.of(genreId, genreMap.get(genreId))); } return result; } private void updateFilmRating(Long mpaId, Long filmId) { - String sqlQuery14 = "update film set ratingId = ? where id = ?"; - jdbcTemplate.update(sqlQuery14, mpaId, filmId); + jdbcTemplate.update(SQL_UPDATE_FILM_RATING, mpaId, filmId); + } + + private void logAndThrowConditionsNotMetException(String message) throws ConditionsNotMetException { + log.error("Exception", new ConditionsNotMetException(message)); + throw new ConditionsNotMetException(message); + } + + private void logAndThrowNotFoundException(String value, String message) throws NotFoundException { + log.error("Exception", new NotFoundException(value, message)); + throw new NotFoundException(value, message); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java index e182c21..bfc8501 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java @@ -8,11 +8,11 @@ public interface FilmStorage { - public List findAll(); + List findAll(); - public FilmRequest findById(Long id); + FilmRequest findById(Long id); - public FilmRequest create(Buffer film); + FilmRequest create(Buffer film); - public FilmRequest update(Buffer newFilm); + FilmRequest update(Buffer newFilm); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/InMemoryFilmStorage.java deleted file mode 100644 index 144b7e2..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/InMemoryFilmStorage.java +++ /dev/null @@ -1,133 +0,0 @@ -//package ru.yandex.practicum.filmorate.storage.film; -// -//import lombok.extern.slf4j.Slf4j; -//import org.springframework.beans.factory.annotation.Autowired; -//import org.springframework.stereotype.Component; -//import ru.yandex.practicum.filmorate.exception.ExceptionMessages; -//import ru.yandex.practicum.filmorate.exception.NotFoundException; -//import ru.yandex.practicum.filmorate.exception.ValidationException; -//import ru.yandex.practicum.filmorate.model.Film; -//import ru.yandex.practicum.filmorate.model.User; -//import ru.yandex.practicum.filmorate.storage.user.UserStorage; -// -//import java.time.LocalDateTime; -//import java.time.chrono.ChronoLocalDate; -//import java.util.*; -//import java.util.stream.Collectors; -// -//@Component -//@Slf4j -//public class InMemoryFilmStorage implements FilmStorage { -// -// private static final Map films = new HashMap<>(); -// private final UserStorage userStorage; -// -// @Autowired -// public InMemoryFilmStorage(UserStorage userStorage) { -// this.userStorage = userStorage; -// } -// -// @Override -// public Collection findAll() { -// log.info("Processing Get-request..."); -// return films.values(); -// } -// -// @Override -// public Film findById(Long id) throws NotFoundException { -// if (id == null) { -// throw new ValidationException(ExceptionMessages.FILM_ID_CANNOT_BE_NULL); -// } -// Film film = films.get(id); -// if (film == null) { -// throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, id)); -// } -// return film; -// } -// -// @Override -// public Film create(Film film) throws ValidationException { -// validateFilm(film); -// film.setId(getNextId()); -// films.put(film.getId(), film); -// return film; -// } -// -// @Override -// public Film update(Film film) throws NotFoundException, ValidationException { -// validateFilm(film); -// Film oldFilm = films.get(film.getId()); -// if (oldFilm == null) { -// throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, film.getId())); -// } -// oldFilm.setName(film.getName()); -// oldFilm.setDescription(film.getDescription()); -// oldFilm.setReleaseDate(film.getReleaseDate()); -// oldFilm.setDuration(film.getDuration()); -// return oldFilm; -// } -// -// @Override -// public void addLike(Long filmId, Long userId) throws NotFoundException { -// Film film = findById(filmId); // Проверяем, существует ли фильм -// if (film == null) { -// throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId)); -// } -// -// User user = userStorage.findById(userId); -// if (user == null) { -// throw new NotFoundException(String.format("not found", userId)); -// } -// -// film.getLikedUsers().add(userId); -// log.info("User with ID = {} liked the film with ID = {}", userId, filmId); -// } -// -// @Override -// public void removeLike(Long filmId, Long userId) throws NotFoundException { -// Film film = findById(filmId); -// if (film == null) { -// throw new NotFoundException(String.format(ExceptionMessages.FILM_NOT_FOUND, filmId)); -// } -// -// User user = userStorage.findById(userId); -// if (user == null) { -// throw new NotFoundException(String.format("not found", userId)); -// } -// -// if (!film.getLikedUsers().contains(userId)) { -// throw new NotFoundException(String.format("User with ID = %d did not like the film with ID = %d", userId, filmId)); -// } -// -// film.getLikedUsers().remove(userId); -// log.info("User with ID = {} unliked the film with ID = {}", userId, filmId); -// } -// -// @Override -// public List getTopFilms(int count) { -// log.info("Getting top-{} films by number of likes", count); -// return films.values().stream() -// .sorted(Comparator.comparingInt(f -> -f.getLikedUsers().size())) -// .limit(count) -// .collect(Collectors.toList()); -// } -// -// private long getNextId() { -// return films.keySet().stream().mapToLong(id -> id).max().orElse(0) + 1; -// } -// -// private void validateFilm(Film film) throws ValidationException { -// if (film.getName() == null || film.getName().isBlank()) { -// throw new ValidationException(ExceptionMessages.FILM_NAME_CANNOT_BE_EMPTY); -// } -// if (film.getDescription() != null && film.getDescription().length() > 200) { -// throw new ValidationException(ExceptionMessages.FILM_DESCRIPTION_TOO_LONG); -// } -// if (film.getReleaseDate().isBefore(ChronoLocalDate.from(LocalDateTime.of(1895, 12, 28, 0, 0, 0)))) { -// throw new ValidationException(ExceptionMessages.FILM_RELEASE_DATE_INVALID); -// } -// if (film.getDuration() <= 0) { -// throw new ValidationException(ExceptionMessages.FILM_DURATION_INVALID); -// } -// } -//} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/InMemoryUserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/InMemoryUserStorage.java deleted file mode 100644 index 91a2843..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/InMemoryUserStorage.java +++ /dev/null @@ -1,183 +0,0 @@ -//package ru.yandex.practicum.filmorate.storage.user; -// -//import lombok.extern.slf4j.Slf4j; -//import org.springframework.stereotype.Component; -//import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; -//import ru.yandex.practicum.filmorate.exception.NotFoundException; -//import ru.yandex.practicum.filmorate.exception.ValidationException; -//import ru.yandex.practicum.filmorate.model.User; -// -//import java.time.LocalDate; -//import java.util.*; -//import java.util.stream.Collectors; -// -//@Component -//@Slf4j -//public class InMemoryUserStorage implements UserStorage { -// private final Map users = new HashMap<>(); -// -// @Override -// public Collection findAll() { -// log.info("Returning the list of users..."); -// return users.values(); -// } -// -// @Override -// public User create(User user) throws ValidationException, DuplicatedDataException { -// validateEmail(user.getEmail()); -// validateLogin(user.getLogin()); -// if (user.getName() == null || user.getName().isBlank()) { -// user.setName(user.getLogin()); -// } -// validateBirthday(user.getBirthday()); -// duplicateCheck(user); -// user.setId(getNextId()); -// user.setFriends(new HashSet<>()); -// users.put(user.getId(), user); -// log.info("User created: {}", user); -// return user; -// } -// -// @Override -// public User update(User newUser) throws NotFoundException, ValidationException { -// if (newUser.getId() == null) { -// throw new ValidationException("User ID cannot be null"); -// } -// if (!users.containsKey(newUser.getId())) { -// throw new NotFoundException("User with ID = " + newUser.getId() + " not found"); -// } -// User oldUser = users.get(newUser.getId()); -// oldUser.setEmail(newUser.getEmail()); -// oldUser.setLogin(newUser.getLogin()); -// oldUser.setName(newUser.getName() != null ? newUser.getName() : newUser.getLogin()); -// oldUser.setBirthday(newUser.getBirthday()); -// -// if (newUser.getFriends() == null) { -// newUser.setFriends(new HashSet<>()); -// } -// oldUser.setFriends(new HashSet<>(newUser.getFriends())); -// -// users.put(oldUser.getId(), oldUser); -// log.info("User with ID = {} updated: {}", oldUser.getId(), oldUser); -// return oldUser; -// } -// -// @Override -// public User findById(Long id) throws NotFoundException { -// if (id == null) { -// throw new ValidationException("ID cannot be null"); -// } -// User user = users.get(id); -// if (user == null) { -// throw new NotFoundException("User with ID = " + id + " not found"); -// } -// log.info("User found: {}", user); -// return user; -// } -// -// @Override -// public void addFriend(Long userId, Long friendId) throws NotFoundException { -// User user = findById(userId); -// User friend = findById(friendId); -// -// if (user.getFriends() == null) { -// user.setFriends(new HashSet<>()); -// } -// if (friend.getFriends() == null) { -// friend.setFriends(new HashSet<>()); -// } -// -// user.getFriends().add(friendId); -// friend.getFriends().add(userId); -// -// update(user); -// update(friend); -// -// log.info("User with ID = {} added as a friend to user with ID = {}", friendId, userId); -// } -// -// @Override -// public User removeFriend(Long userId, Long friendId) throws NotFoundException { -// User user = findById(userId); -// User friend = findById(friendId); -// -// if (user.getFriends() == null) { -// user.setFriends(new HashSet<>()); -// } -// if (friend.getFriends() == null) { -// friend.setFriends(new HashSet<>()); -// } -// -// user.getFriends().remove(friendId); -// friend.getFriends().remove(userId); -// -// log.info("User with ID = {} has been removed from friends of user with ID = {}", friendId, userId); -// return user; -// } -// -// @Override -// public Collection getFriends(Long id) throws NotFoundException { -// User user = findById(id); -// -// if (user.getFriends() == null || user.getFriends().isEmpty()) { -// return Collections.emptyList(); -// } -// -// return user.getFriends().stream() -// .map(this::findById) -// .collect(Collectors.toList()); -// } -// -// @Override -// public Collection getCommonFriends(Long userId, Long otherUserId) throws NotFoundException { -// User user = findById(userId); -// User otherUser = findById(otherUserId); -// -// if (user.getFriends() == null) { -// user.setFriends(new HashSet<>()); -// } -// if (otherUser.getFriends() == null) { -// otherUser.setFriends(new HashSet<>()); -// } -// -// Set commonFriendIds = new HashSet<>(user.getFriends()); -// commonFriendIds.retainAll(otherUser.getFriends()); -// -// return commonFriendIds.stream() -// .map(this::findById) -// .collect(Collectors.toList()); -// } -// -// private long getNextId() { -// return users.keySet().stream().mapToLong(id -> id).max().orElse(0) + 1; -// } -// -// private void duplicateCheck(User user) throws DuplicatedDataException { -// for (User u : users.values()) { -// if (u.getEmail().equals(user.getEmail())) { -// throw new DuplicatedDataException("A user with this email already exists"); -// } -// } -// } -// -// private void validateEmail(String email) throws ValidationException { -// if (email == null || email.isBlank() || !email.contains("@") || email.contains(" ") || email.length() < 2) { -// throw new ValidationException("Invalid email"); -// } -// } -// -// private void validateLogin(String login) throws ValidationException { -// if (login == null || login.isBlank() || login.contains(" ")) { -// throw new ValidationException("Login cannot be empty or contain spaces"); -// } -// } -// -// private void validateBirthday(LocalDate birthday) throws ValidationException { -// if (birthday == null) { -// throw new ValidationException("Birthday cannot be null"); -// } -// if (birthday.isAfter(LocalDate.now())) { -// throw new ValidationException("Birthday cannot be in the future"); -// } -// } -//} \ No newline at end of file From d01fd5df4d102ebe1daa22a4ec9f7c7d41036107 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 18:06:23 +0500 Subject: [PATCH 031/118] =?UTF-8?q?=D1=80=D0=B5=D1=84=D1=80=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/service/GenreService.java | 2 +- .../practicum/filmorate/service/MpaService.java | 2 +- .../storage/{film => genre}/GenreDbStorage.java | 4 ++-- .../filmorate/storage/genre/GenreStorage.java | 13 +++++++++++++ .../storage/{film => mpa}/MpaDbStorage.java | 4 ++-- .../practicum/filmorate/storage/mpa/MpaStorage.java | 13 +++++++++++++ 6 files changed, 32 insertions(+), 6 deletions(-) rename src/main/java/ru/yandex/practicum/filmorate/storage/{film => genre}/GenreDbStorage.java (91%) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/genre/GenreStorage.java rename src/main/java/ru/yandex/practicum/filmorate/storage/{film => mpa}/MpaDbStorage.java (91%) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/mpa/MpaStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java index 1079bdf..3c35f6e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java @@ -3,7 +3,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import ru.yandex.practicum.filmorate.model.Genre; -import ru.yandex.practicum.filmorate.storage.film.GenreDbStorage; +import ru.yandex.practicum.filmorate.storage.genre.GenreDbStorage; import java.util.List; diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java index 312ea3d..fa8d754 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java @@ -3,7 +3,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import ru.yandex.practicum.filmorate.model.Mpa; -import ru.yandex.practicum.filmorate.storage.film.MpaDbStorage; +import ru.yandex.practicum.filmorate.storage.mpa.MpaDbStorage; import java.util.List; diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/GenreDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/genre/GenreDbStorage.java similarity index 91% rename from src/main/java/ru/yandex/practicum/filmorate/storage/film/GenreDbStorage.java rename to src/main/java/ru/yandex/practicum/filmorate/storage/genre/GenreDbStorage.java index 9b9584e..ab4d25f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/GenreDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/genre/GenreDbStorage.java @@ -1,4 +1,4 @@ -package ru.yandex.practicum.filmorate.storage.film; +package ru.yandex.practicum.filmorate.storage.genre; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; @@ -10,7 +10,7 @@ import java.util.List; @Repository -public class GenreDbStorage { +public class GenreDbStorage implements GenreStorage { private final JdbcTemplate jdbcTemplate; diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/genre/GenreStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/genre/GenreStorage.java new file mode 100644 index 0000000..f4f10dd --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/genre/GenreStorage.java @@ -0,0 +1,13 @@ +package ru.yandex.practicum.filmorate.storage.genre; + +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Genre; + +import java.util.List; + +public interface GenreStorage { + + Genre getGenreById(Long id) throws NotFoundException; + + List getAllGenres(); +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/MpaDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/mpa/MpaDbStorage.java similarity index 91% rename from src/main/java/ru/yandex/practicum/filmorate/storage/film/MpaDbStorage.java rename to src/main/java/ru/yandex/practicum/filmorate/storage/mpa/MpaDbStorage.java index 08036ab..4b833c3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/MpaDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/mpa/MpaDbStorage.java @@ -1,4 +1,4 @@ -package ru.yandex.practicum.filmorate.storage.film; +package ru.yandex.practicum.filmorate.storage.mpa; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; @@ -10,7 +10,7 @@ import java.util.List; @Repository -public class MpaDbStorage { +public class MpaDbStorage implements MpaStorage { private final JdbcTemplate jdbcTemplate; diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/mpa/MpaStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/mpa/MpaStorage.java new file mode 100644 index 0000000..0e852aa --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/mpa/MpaStorage.java @@ -0,0 +1,13 @@ +package ru.yandex.practicum.filmorate.storage.mpa; + +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Mpa; + +import java.util.List; + +public interface MpaStorage { + + Mpa getMpaById(Long id) throws NotFoundException; + + List getAllMpa(); +} \ No newline at end of file From 84cbfe81196459e8a1de2519abefda263bbc55a8 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 18:10:41 +0500 Subject: [PATCH 032/118] =?UTF-8?q?=D0=B2=D1=81=D0=B5=20=D0=B5=D1=89=D0=B5?= =?UTF-8?q?=20=D0=B4=D0=B5=D0=BB=D0=B0=D0=B5=D0=BC=20=D0=BA=D0=BE=D0=B4=20?= =?UTF-8?q?=D0=BA=D1=80=D0=B0=D1=81=D0=B8=D0=B2=D1=8B=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/UserService.java | 131 +++++++++++------- 1 file changed, 81 insertions(+), 50 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index e80631f..1b3be74 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -22,76 +22,107 @@ @ConfigurationPropertiesScan @RequiredArgsConstructor public class UserService implements UserInterface { + + //sQL-запросы + private static final String SQL_SELECT_FRIENDS = "select userId, friendId from friends"; + private static final String SQL_INSERT_FRIEND = "insert into friends(userId, friendId) values (?, ?)"; + private static final String SQL_DELETE_FRIEND = "delete from friends where userId = ? and friendId = ?"; + + //сообщения для логирования и исключений + private static final String LOG_POST_REQUEST = "Обработка Post-запроса..."; + private static final String LOG_DELETE_REQUEST = "Обработка Del-запроса..."; + private static final String LOG_GET_REQUEST = "Обработка Get-запроса..."; + private static final String ERROR_FRIEND_ALREADY_ADDED = "Пользователь с id %d уже добавлен в друзья"; + private static final String ERROR_USER_NOT_FOUND = "Пользователь с данным идентификатором отсутствует в базе"; + @Autowired @Qualifier("UserDbStorage") - UserStorage userStorage; + private final UserStorage userStorage; private final JdbcTemplate jdbcTemplate; - @Override - public User addFriend(Long idUser, Long idFriend) throws ConditionsNotMetException { - log.info("Обработка Post-запроса..."); - String sqlQuery2 = "select userId, friendId from friends"; - Map> friends = jdbcTemplate.query(sqlQuery2, new UserDbStorage.FriendsExtractor()); - - if (friends.get(idUser) != null && friends.get(idUser).contains(idFriend)) { - log.error("Exception", new ConditionsNotMetException(idFriend.toString())); - throw new ConditionsNotMetException(idFriend.toString()); - } - if (userStorage.findById(idFriend) == null) { - log.error("Exception", new NotFoundException(idFriend.toString(), "Пользователь с данным идентификатором отсутствует в базе")); - throw new NotFoundException(idFriend.toString(), "Пользователь с данным идентификатором отсутствует в базе"); + public User addFriend(Long idUser, Long idFriend) throws ConditionsNotMetException, NotFoundException { + log.info(LOG_POST_REQUEST); + + validateUserExists(idUser); + validateUserExists(idFriend); + + if (isFriend(idUser, idFriend)) { + logAndThrowConditionsNotMetException(String.format(ERROR_FRIEND_ALREADY_ADDED, idFriend)); } - String sqlQuery = "insert into friends(userId, friendId) " + "values (?, ?)"; - jdbcTemplate.update(sqlQuery, idUser, idFriend); - return userStorage.findById(idUser); + jdbcTemplate.update(SQL_INSERT_FRIEND, idUser, idFriend); + return userStorage.findById(idUser); } @Override - public User delFriend(Long idUser, Long idFriend) throws ConditionsNotMetException { - log.info("Обработка Del-запроса..."); - String sqlQuery = "delete from friends where userId = ? and friendId = ?"; - jdbcTemplate.update(sqlQuery, idUser, idFriend); - if (userStorage.findById(idUser) == null) { - log.error("Exception", new NotFoundException(idUser.toString(), "Пользователь с данным идентификатором отсутствует в базе")); - throw new NotFoundException(idUser.toString(), "Пользователь с данным идентификатором отсутствует в базе"); - } - if (userStorage.findById(idFriend) == null) { - log.error("Exception", new NotFoundException(idUser.toString(), "Пользователь с данным идентификатором отсутствует в базе")); - throw new NotFoundException(idUser.toString(), "Пользователь с данным идентификатором отсутствует в базе"); - } + public User delFriend(Long idUser, Long idFriend) throws NotFoundException { + log.info(LOG_DELETE_REQUEST); + + validateUserExists(idUser); + validateUserExists(idFriend); + + jdbcTemplate.update(SQL_DELETE_FRIEND, idUser, idFriend); return userStorage.findById(idUser); } @Override public Set findJointFriends(Long idUser, Long idFriend) throws NotFoundException { - log.info("Обработка Get-запроса..."); - String sqlQuery2 = "select userId, friendId from friends"; - Map> friends = jdbcTemplate.query(sqlQuery2, new UserDbStorage.FriendsExtractor()); - Set result = new HashSet<>(friends.get(idUser)); - result.retainAll(friends.get(idFriend)); - Set set = new HashSet<>(); - for (Long f : result) - set.add(userStorage.findById(f)); - return set; + log.info(LOG_GET_REQUEST); + + validateUserExists(idUser); + validateUserExists(idFriend); + + Map> friends = jdbcTemplate.query(SQL_SELECT_FRIENDS, new UserDbStorage.FriendsExtractor()); + Set userFriends = friends.getOrDefault(idUser, new HashSet<>()); + Set friendFriends = friends.getOrDefault(idFriend, new HashSet<>()); + + Set jointFriends = new HashSet<>(userFriends); + jointFriends.retainAll(friendFriends); + + Set result = new HashSet<>(); + for (Long friendId : jointFriends) { + result.add(userStorage.findById(friendId)); + } + return result; } @Override public Set findAllFriends(Long idUser) throws NotFoundException { - log.info("Обработка Get-запроса..."); - String sqlQuery2 = "select userId, friendId from friends"; - Map> friends = jdbcTemplate.query(sqlQuery2, new UserDbStorage.FriendsExtractor()); - if (userStorage.findById(idUser) == null) { - log.error("Exception", new NotFoundException(idUser.toString(), "Пользователь с данным идентификатором отсутствует в базе")); - throw new NotFoundException(idUser.toString(), "Пользователь с данным идентификатором отсутствует в базе"); + log.info(LOG_GET_REQUEST); + + validateUserExists(idUser); + + Map> friends = jdbcTemplate.query(SQL_SELECT_FRIENDS, new UserDbStorage.FriendsExtractor()); + assert friends != null; + Set userFriends = friends.getOrDefault(idUser, new HashSet<>()); + + Set result = new HashSet<>(); + for (Long friendId : userFriends) { + result.add(userStorage.findById(friendId)); } - if (friends.get(idUser) == null) return new HashSet<>(); - else { - Set set = new HashSet<>(); - for (Long f : friends.get(idUser)) - set.add(userStorage.findById(f)); - return set; + return result; + } + + private void validateUserExists(Long userId) throws NotFoundException { + if (userStorage.findById(userId) == null) { + logAndThrowNotFoundException(userId.toString()); } } + + private boolean isFriend(Long idUser, Long idFriend) { + Map> friends = jdbcTemplate.query(SQL_SELECT_FRIENDS, new UserDbStorage.FriendsExtractor()); + assert friends != null; + return friends.getOrDefault(idUser, new HashSet<>()).contains(idFriend); + } + + private void logAndThrowConditionsNotMetException(String message) throws ConditionsNotMetException { + log.error("Exception", new ConditionsNotMetException(message)); + throw new ConditionsNotMetException(message); + } + + private void logAndThrowNotFoundException(String value) throws NotFoundException { + log.error("Exception", new NotFoundException(value, UserService.ERROR_USER_NOT_FOUND)); + throw new NotFoundException(value, UserService.ERROR_USER_NOT_FOUND); + } } \ No newline at end of file From 086367010063f82aac10bc9d225278ff53282352 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sat, 1 Mar 2025 18:28:22 +0500 Subject: [PATCH 033/118] =?UTF-8?q?=D0=BF=D0=BE=D0=B1=D0=B0=D0=BB=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BB=D0=B0=D1=81=D1=8C=20=D1=81=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=86=D0=B8=D0=B5?= =?UTF-8?q?=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 90 ++++++++++------- .../filmorate/controller/GenreController.java | 26 ++--- .../filmorate/controller/MpaController.java | 27 +++--- .../filmorate/controller/UserController.java | 97 ++++++++++++++++--- .../exception/ExceptionMessages.java | 11 --- 5 files changed, 166 insertions(+), 85 deletions(-) delete mode 100644 src/main/java/ru/yandex/practicum/filmorate/exception/ExceptionMessages.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index f6c868f..58b26d7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -21,20 +21,21 @@ @RestController @RequestMapping("/films") - public class FilmController { - @Autowired - @Qualifier("FilmDbStorage") - private final FilmStorage filmStorage; - @Autowired - @Qualifier("UserDbStorage") - private final UserStorage userStorage; + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static final String DEFAULT_GENRE = "нет жанра"; + private final FilmStorage filmStorage; + private final UserStorage userStorage; private final FilmInterface filmInterface; @Autowired - public FilmController(FilmStorage filmStorage, UserStorage userStorage, FilmInterface filmInterface) { + public FilmController( + @Qualifier("FilmDbStorage") FilmStorage filmStorage, + @Qualifier("UserDbStorage") UserStorage userStorage, + FilmInterface filmInterface + ) { this.filmStorage = filmStorage; this.userStorage = userStorage; this.filmInterface = filmInterface; @@ -53,37 +54,14 @@ public FilmRequest findById(@PathVariable("id") Long id) throws ConditionsNotMet @PostMapping @ResponseStatus(HttpStatus.CREATED) public FilmRequest create(@Valid @RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NullPointerException { - String name = objectNode.get("name").asText(); - String description = objectNode.get("description").asText(); - String releaseDate = objectNode.get("releaseDate").asText(); - Integer duration = objectNode.get("duration").asInt(); - List mpa = objectNode.get("mpa").findValuesAsText("id"); - List genres = new ArrayList<>(); - try { - genres = objectNode.get("genres").findValuesAsText("id"); - } catch (NullPointerException e) { - genres = List.of("нет жанра"); - } finally { - return filmStorage.create(Buffer.of(Long.valueOf(0), name, description, LocalDate.parse(releaseDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")), duration, genres, Long.valueOf(mpa.get(0).toString()))); - } + Buffer buffer = parseObjectNodeToBuffer(objectNode); + return filmStorage.create(buffer); } @PutMapping public FilmRequest update(@Valid @RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NotFoundException { - Long id = objectNode.get("id").asLong(); - String name = objectNode.get("name").asText(); - String description = objectNode.get("description").asText(); - String releaseDate = objectNode.get("releaseDate").asText(); - Integer duration = objectNode.get("duration").asInt(); - List mpa = objectNode.get("mpa").findValuesAsText("id"); - List genres = new ArrayList<>(); - try { - genres = objectNode.get("genres").findValuesAsText("id"); - } catch (NullPointerException e) { - genres = List.of("нет жанра"); - } finally { - return filmStorage.update(Buffer.of(id, name, description, LocalDate.parse(releaseDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")), duration, genres, Long.valueOf(mpa.get(0).toString()))); - } + Buffer buffer = parseObjectNodeToBuffer(objectNode); + return filmStorage.update(buffer); } @PutMapping("/{id}/like/{userId}") @@ -97,7 +75,47 @@ public FilmRequest delLike(@Valid @PathVariable("id") Long id, @PathVariable("us } @GetMapping("/popular") - public LinkedHashSet viewRaiting(@RequestParam(required = false) Long count) throws NotFoundException { + public LinkedHashSet viewRating(@RequestParam(required = false) Long count) throws NotFoundException { return filmInterface.viewRating(count); } + + /** + * преобразует json объект в объект Buffer + * + * @param objectNode json объект + * @return объект Buffer + */ + private Buffer parseObjectNodeToBuffer(ObjectNode objectNode) { + Long id = objectNode.has("id") ? objectNode.get("id").asLong() : 0L; + String name = objectNode.get("name").asText(); + String description = objectNode.get("description").asText(); + String releaseDate = objectNode.get("releaseDate").asText(); + Integer duration = objectNode.get("duration").asInt(); + List mpa = objectNode.get("mpa").findValuesAsText("id"); + List genres = extractGenresFromObjectNode(objectNode); + + return Buffer.of( + id, + name, + description, + LocalDate.parse(releaseDate, DATE_FORMATTER), + duration, + genres, + Long.valueOf(mpa.get(0)) + ); + } + + /** + * извлекает список жанров из json объекта + * + * @param objectNode json объект + * @return список жанров + */ + private List extractGenresFromObjectNode(ObjectNode objectNode) { + try { + return objectNode.get("genres").findValuesAsText("id"); + } catch (NullPointerException e) { + return List.of(DEFAULT_GENRE); + } + } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java index c4aa356..5d1ed35 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java @@ -1,10 +1,7 @@ package ru.yandex.practicum.filmorate.controller; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.service.GenreService; @@ -12,22 +9,29 @@ @RestController @RequestMapping("/genres") +@RequiredArgsConstructor public class GenreController { private final GenreService genreService; - @Autowired - public GenreController(GenreService genreService) { - this.genreService = genreService; - } - + /** + * получить жанр по его идентификатору + * + * @param id идентификатор жанра + * @return объект жанра + */ @GetMapping("/{id}") public Genre getGenreById(@PathVariable Long id) { return genreService.getGenreById(id); } + /** + * получить список всех жанров + * + * @return список всех жанров + */ @GetMapping public List getAllGenres() { return genreService.getAllGenres(); } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java index ddf9c92..6561c16 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java @@ -1,10 +1,7 @@ package ru.yandex.practicum.filmorate.controller; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.model.Mpa; import ru.yandex.practicum.filmorate.service.MpaService; @@ -12,23 +9,29 @@ @RestController @RequestMapping("/mpa") +@RequiredArgsConstructor public class MpaController { private final MpaService mpaService; - @Autowired - public MpaController(MpaService mpaService) { - this.mpaService = mpaService; - } - + /** + * получить рейтинг mpa по его идентификатору + * + * @param id идентификатор рейтинга mpa + * @return объект рейтинга mpa + */ @GetMapping("/{id}") public Mpa getMpaById(@PathVariable Long id) { return mpaService.getMpaById(id); } + /** + * получить список всех рейтингов mpa + * + * @return список всех рейтингов mpa + */ @GetMapping public List getAllMpa() { return mpaService.getAllMpa(); } -} - +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index d000423..af09875 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -1,7 +1,7 @@ package ru.yandex.practicum.filmorate.controller; import jakarta.validation.Valid; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @@ -17,57 +17,124 @@ @RestController @RequestMapping("/users") - +@RequiredArgsConstructor public class UserController { - @Autowired + + private static final String USER_ID_PATH = "/{id}"; + private static final String FRIENDS_PATH = USER_ID_PATH + "/friends"; + private static final String FRIEND_ID_PATH = FRIENDS_PATH + "/{friendId}"; + private static final String COMMON_FRIENDS_PATH = USER_ID_PATH + "/friends/common/{otherId}"; + @Qualifier("UserDbStorage") private final UserStorage userStorage; private final UserInterface userInterface; - @Autowired - public UserController(UserStorage userStorage, UserInterface userInterface) { - this.userStorage = userStorage; - this.userInterface = userInterface; - } - + /** + * получить список всех пользователей + * + * @return список всех пользователей + */ @GetMapping public Collection findAll() { return userStorage.findAll(); } - @GetMapping("/{id}") + /** + * получить пользователя по его ид + * + * @param id идентификатор пользователя + * @return объект пользователя + * @throws ConditionsNotMetException если идентификатор пользователя некорректен + */ + @GetMapping(USER_ID_PATH) public User findById(@PathVariable("id") Long id) throws ConditionsNotMetException { return userStorage.findById(id); } + /** + * создать нового пользователя + * + * @param user объект пользователя + * @return созданный пользователь + * @throws ConditionsNotMetException если данные пользователя некорректны + * @throws DuplicatedDataException если email пользователя уже используется + */ @PostMapping @ResponseStatus(HttpStatus.CREATED) public User create(@Valid @RequestBody User user) throws ConditionsNotMetException, DuplicatedDataException { return userStorage.create(user); } + /** + * обновить данные пользователя + * + * @param newUser объект пользователя с новыми данными + * @return обновленный пользователь + * @throws ConditionsNotMetException если данные пользователя некорректны + * @throws NotFoundException если пользователь с указанным id не найден + * @throws DuplicatedDataException если email пользователя уже используется + */ @PutMapping public User update(@Valid @RequestBody User newUser) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { return userStorage.update(newUser); } - @PutMapping("/{id}/friends/{friendId}") + /** + * добавить друга пользователю + * + * @param id идентификатор пользователя + * @param friendId идентификатор друга + * @return пользователь с обновленным списком друзей + * @throws ConditionsNotMetException если пользователь уже добавлен в друзья + * @throws NotFoundException если пользователь или друг не найдены + * @throws DuplicatedDataException если email пользователя уже используется + */ + @PutMapping(FRIEND_ID_PATH) public User addFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { return userInterface.addFriend(id, friendId); } - @DeleteMapping("/{id}/friends/{friendId}") + /** + * удалить друга у пользователя + * + * @param id идентификатор пользователя + * @param friendId идентификатор друга + * @return пользователь с обновленным списком друзей + * @throws ConditionsNotMetException если пользователь не найден в списке друзей + * @throws NotFoundException если пользователь или друг не найдены + * @throws DuplicatedDataException если email пользователя уже используется + */ + @DeleteMapping(FRIEND_ID_PATH) public User delFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { return userInterface.delFriend(id, friendId); } - @GetMapping("/{id}/friends/common/{otherId}") + /** + * получить список общих друзей двух пользователей + * + * @param id идентификатор первого пользователя + * @param otherId идентификатор второго пользователя + * @return список общих друзей + * @throws ConditionsNotMetException если пользователи не найдены + * @throws NotFoundException если пользователи не найдены + * @throws DuplicatedDataException если email пользователя уже используется + */ + @GetMapping(COMMON_FRIENDS_PATH) public Set findJointFriends(@Valid @PathVariable("id") Long id, @PathVariable("otherId") Long otherId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { return userInterface.findJointFriends(id, otherId); } - @GetMapping("/{id}/friends") - public Set findJointFriends(@Valid @PathVariable("id") Long id) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + /** + * получить список друзей пользователя + * + * @param id идентификатор пользователя + * @return список друзей + * @throws ConditionsNotMetException если пользователь не найден + * @throws NotFoundException если пользователь не найден + * @throws DuplicatedDataException если email пользователя уже используется + */ + @GetMapping(FRIENDS_PATH) + public Set findAllFriends(@Valid @PathVariable("id") Long id) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { return userInterface.findAllFriends(id); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ExceptionMessages.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ExceptionMessages.java deleted file mode 100644 index af7a70f..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/ExceptionMessages.java +++ /dev/null @@ -1,11 +0,0 @@ -package ru.yandex.practicum.filmorate.exception; - -public class ExceptionMessages { - - public static final String FILM_ID_CANNOT_BE_NULL = "Film ID cannot be null"; - public static final String FILM_NOT_FOUND = "Film with id %d not found"; - public static final String FILM_NAME_CANNOT_BE_EMPTY = "Film name cannot be empty"; - public static final String FILM_DURATION_INVALID = "Film duration must be a positive number"; - public static final String FILM_DESCRIPTION_TOO_LONG = "Film description cannot exceed 200 characters"; - public static final String FILM_RELEASE_DATE_INVALID = "Film release date cannot be earlier than December 28, 1895"; -} \ No newline at end of file From 264bb8fb93c1d532f87cc2879305a9d214f46caa Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 15:34:14 +0500 Subject: [PATCH 034/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BD=D1=8B=20?= =?UTF-8?q?=D0=B2=D1=8B=D0=B1=D1=80=D0=BE=D1=81=D1=8B=20=D0=B8=D1=81=D0=BA?= =?UTF-8?q?=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 12 ++++++------ .../filmorate/controller/UserController.java | 14 +++++++------- .../practicum/filmorate/service/FilmService.java | 14 +++++++------- .../practicum/filmorate/service/UserService.java | 14 +++++++------- .../filmorate/storage/film/FilmDbStorage.java | 12 ++++++------ .../filmorate/storage/user/UserDbStorage.java | 6 +++--- 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 58b26d7..e1f4251 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -47,35 +47,35 @@ public List findAll() { } @GetMapping("/{id}") - public FilmRequest findById(@PathVariable("id") Long id) throws ConditionsNotMetException, NotFoundException { + public FilmRequest findById(@PathVariable("id") Long id) { return filmStorage.findById(id); } @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmRequest create(@Valid @RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NullPointerException { + public FilmRequest create(@Valid @RequestBody ObjectNode objectNode) { Buffer buffer = parseObjectNodeToBuffer(objectNode); return filmStorage.create(buffer); } @PutMapping - public FilmRequest update(@Valid @RequestBody ObjectNode objectNode) throws ConditionsNotMetException, NotFoundException { + public FilmRequest update(@Valid @RequestBody ObjectNode objectNode) { Buffer buffer = parseObjectNodeToBuffer(objectNode); return filmStorage.update(buffer); } @PutMapping("/{id}/like/{userId}") - public FilmRequest addLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) throws ConditionsNotMetException { + public FilmRequest addLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { return filmInterface.addLike(userId, id); } @DeleteMapping("/{id}/like/{userId}") - public FilmRequest delLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) throws NotFoundException { + public FilmRequest delLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { return filmInterface.delLike(userId, id); } @GetMapping("/popular") - public LinkedHashSet viewRating(@RequestParam(required = false) Long count) throws NotFoundException { + public LinkedHashSet viewRating(@RequestParam(required = false) Long count) { return filmInterface.viewRating(count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index af09875..4bb6d76 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -47,7 +47,7 @@ public Collection findAll() { * @throws ConditionsNotMetException если идентификатор пользователя некорректен */ @GetMapping(USER_ID_PATH) - public User findById(@PathVariable("id") Long id) throws ConditionsNotMetException { + public User findById(@PathVariable("id") Long id) { return userStorage.findById(id); } @@ -61,7 +61,7 @@ public User findById(@PathVariable("id") Long id) throws ConditionsNotMetExcepti */ @PostMapping @ResponseStatus(HttpStatus.CREATED) - public User create(@Valid @RequestBody User user) throws ConditionsNotMetException, DuplicatedDataException { + public User create(@Valid @RequestBody User user) { return userStorage.create(user); } @@ -75,7 +75,7 @@ public User create(@Valid @RequestBody User user) throws ConditionsNotMetExcepti * @throws DuplicatedDataException если email пользователя уже используется */ @PutMapping - public User update(@Valid @RequestBody User newUser) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + public User update(@Valid @RequestBody User newUser) { return userStorage.update(newUser); } @@ -90,7 +90,7 @@ public User update(@Valid @RequestBody User newUser) throws ConditionsNotMetExce * @throws DuplicatedDataException если email пользователя уже используется */ @PutMapping(FRIEND_ID_PATH) - public User addFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + public User addFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) { return userInterface.addFriend(id, friendId); } @@ -105,7 +105,7 @@ public User addFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendI * @throws DuplicatedDataException если email пользователя уже используется */ @DeleteMapping(FRIEND_ID_PATH) - public User delFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + public User delFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) { return userInterface.delFriend(id, friendId); } @@ -120,7 +120,7 @@ public User delFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendI * @throws DuplicatedDataException если email пользователя уже используется */ @GetMapping(COMMON_FRIENDS_PATH) - public Set findJointFriends(@Valid @PathVariable("id") Long id, @PathVariable("otherId") Long otherId) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + public Set findJointFriends(@Valid @PathVariable("id") Long id, @PathVariable("otherId") Long otherId) { return userInterface.findJointFriends(id, otherId); } @@ -134,7 +134,7 @@ public Set findJointFriends(@Valid @PathVariable("id") Long id, @PathVaria * @throws DuplicatedDataException если email пользователя уже используется */ @GetMapping(FRIENDS_PATH) - public Set findAllFriends(@Valid @PathVariable("id") Long id) throws ConditionsNotMetException, NotFoundException, DuplicatedDataException { + public Set findAllFriends(@Valid @PathVariable("id") Long id) { return userInterface.findAllFriends(id); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index bbd1b9f..b054c0b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -53,7 +53,7 @@ public LinkedHashMap extractData(ResultSet rs) throws SQLException { } @Override - public FilmRequest addLike(Long idUser, Long idFilm) throws ConditionsNotMetException { + public FilmRequest addLike(Long idUser, Long idFilm) { log.info("Обработка Post-запроса..."); if (userStorage.findById(idUser) != null && filmStorage.findById(idFilm) != null) { Map> likedUsers = jdbcTemplate.query(sqlQuery1, new FilmDbStorage.LikedUsersExtractor()); @@ -75,7 +75,7 @@ public FilmRequest addLike(Long idUser, Long idFilm) throws ConditionsNotMetExce } @Override - public FilmRequest delLike(Long idUser, Long idFilm) throws ConditionsNotMetException { + public FilmRequest delLike(Long idUser, Long idFilm) { log.info("Обработка Del-запроса..."); if (userStorage.findById(idUser) != null && filmStorage.findById(idFilm) != null) { Map> likedUsers = jdbcTemplate.query(sqlQuery1, new FilmDbStorage.LikedUsersExtractor()); @@ -98,7 +98,7 @@ public List viewRaiting(Long count) { return List.of(); } - public LinkedHashSet viewRating(Long count) throws NotFoundException { + public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); LinkedHashMap likedUsers = jdbcTemplate.query(sqlQuery5, new TopLikedUsersExtractor()); LinkedHashSet films = new LinkedHashSet<>(); @@ -119,7 +119,7 @@ public LinkedHashSet viewRating(Long count) throws NotFoundExceptio return films; } - public List viewGenre() throws NotFoundException { + public List viewGenre() { log.info("Обработка Get-запроса..."); Map genre = jdbcTemplate.query(sqlQuery6, new GenreExtractor()); List genreConstant = new ArrayList<>(); @@ -141,7 +141,7 @@ public Map extractData(ResultSet rs) throws SQLException { } } - public GenreConstant viewGenreName(Long id) throws NotFoundException { + public GenreConstant viewGenreName(Long id) { log.info("Обработка Get-запроса..."); Map genre = jdbcTemplate.query(sqlQuery7, new GenreExtractor(), id); if (id < 0 || id > 7) { @@ -150,7 +150,7 @@ public GenreConstant viewGenreName(Long id) throws NotFoundException { } else return GenreConstant.of(id, genre.get(id)); } - public List viewFilmsRating() throws NotFoundException { + public List viewFilmsRating() { log.info("Обработка Get-запроса..."); Map genre = jdbcTemplate.query(sqlQuery8, new RatingNameExtractor()); List mpaConstant = new ArrayList<>(); @@ -172,7 +172,7 @@ public Map extractData(ResultSet rs) throws SQLException { } } - public MpaConstant viewRatingName(Long id) throws NotFoundException { + public MpaConstant viewRatingName(Long id) { log.info("Обработка Get-запроса..."); Map genre = jdbcTemplate.query(sqlQuery9, new RatingNameExtractor(), id); if (id < 0 || id > 6) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 1b3be74..2415f3f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -41,7 +41,7 @@ public class UserService implements UserInterface { private final JdbcTemplate jdbcTemplate; @Override - public User addFriend(Long idUser, Long idFriend) throws ConditionsNotMetException, NotFoundException { + public User addFriend(Long idUser, Long idFriend) { log.info(LOG_POST_REQUEST); validateUserExists(idUser); @@ -56,7 +56,7 @@ public User addFriend(Long idUser, Long idFriend) throws ConditionsNotMetExcepti } @Override - public User delFriend(Long idUser, Long idFriend) throws NotFoundException { + public User delFriend(Long idUser, Long idFriend) { log.info(LOG_DELETE_REQUEST); validateUserExists(idUser); @@ -67,7 +67,7 @@ public User delFriend(Long idUser, Long idFriend) throws NotFoundException { } @Override - public Set findJointFriends(Long idUser, Long idFriend) throws NotFoundException { + public Set findJointFriends(Long idUser, Long idFriend) { log.info(LOG_GET_REQUEST); validateUserExists(idUser); @@ -88,7 +88,7 @@ public Set findJointFriends(Long idUser, Long idFriend) throws NotFoundExc } @Override - public Set findAllFriends(Long idUser) throws NotFoundException { + public Set findAllFriends(Long idUser) { log.info(LOG_GET_REQUEST); validateUserExists(idUser); @@ -104,7 +104,7 @@ public Set findAllFriends(Long idUser) throws NotFoundException { return result; } - private void validateUserExists(Long userId) throws NotFoundException { + private void validateUserExists(Long userId) { if (userStorage.findById(userId) == null) { logAndThrowNotFoundException(userId.toString()); } @@ -116,12 +116,12 @@ private boolean isFriend(Long idUser, Long idFriend) { return friends.getOrDefault(idUser, new HashSet<>()).contains(idFriend); } - private void logAndThrowConditionsNotMetException(String message) throws ConditionsNotMetException { + private void logAndThrowConditionsNotMetException(String message) { log.error("Exception", new ConditionsNotMetException(message)); throw new ConditionsNotMetException(message); } - private void logAndThrowNotFoundException(String value) throws NotFoundException { + private void logAndThrowNotFoundException(String value) { log.error("Exception", new NotFoundException(value, UserService.ERROR_USER_NOT_FOUND)); throw new NotFoundException(value, UserService.ERROR_USER_NOT_FOUND); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 8bd73dd..71e3f33 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -126,7 +126,7 @@ public List findAll() { } @Override - public FilmRequest findById(Long id) throws ConditionsNotMetException, NotFoundException { + public FilmRequest findById(Long id) { log.info(LOG_GET_REQUEST); if (id == null || id == 0) { logAndThrowConditionsNotMetException(ERROR_NULL_ID); @@ -168,7 +168,7 @@ public FilmRequest findById(Long id) throws ConditionsNotMetException, NotFoundE } @Override - public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException, NullPointerException { + public FilmRequest create(@Valid Buffer buffer) { log.info(LOG_CREATE_REQUEST); validateBuffer(buffer); @@ -185,7 +185,7 @@ public FilmRequest create(@Valid Buffer buffer) throws ConditionsNotMetException } @Override - public FilmRequest update(@Valid Buffer newFilm) throws ConditionsNotMetException, NotFoundException { + public FilmRequest update(@Valid Buffer newFilm) { log.info(LOG_UPDATE_REQUEST); if (newFilm.getId() == null) { logAndThrowConditionsNotMetException("Id должен быть указан"); @@ -213,7 +213,7 @@ public FilmRequest update(@Valid Buffer newFilm) throws ConditionsNotMetExceptio oldFilm.getDuration(), new HashSet<>(), Mpa.of(newFilm.getMpa(), rating.get(newFilm.getMpa())), genres); } - private void validateBuffer(Buffer buffer) throws ConditionsNotMetException, NullPointerException { + private void validateBuffer(Buffer buffer) { if (buffer.getName() == null || buffer.getName().isBlank()) { logAndThrowConditionsNotMetException(ERROR_EMPTY_NAME); } @@ -256,12 +256,12 @@ private void updateFilmRating(Long mpaId, Long filmId) { jdbcTemplate.update(SQL_UPDATE_FILM_RATING, mpaId, filmId); } - private void logAndThrowConditionsNotMetException(String message) throws ConditionsNotMetException { + private void logAndThrowConditionsNotMetException(String message) { log.error("Exception", new ConditionsNotMetException(message)); throw new ConditionsNotMetException(message); } - private void logAndThrowNotFoundException(String value, String message) throws NotFoundException { + private void logAndThrowNotFoundException(String value, String message) { log.error("Exception", new NotFoundException(value, message)); throw new NotFoundException(value, message); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index a7e3b93..b82d3c6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -80,7 +80,7 @@ public Collection findAll() { return users; } - public User findById(Long id) throws ConditionsNotMetException { + public User findById(Long id) { log.info("Обработка Get-запроса..."); if (id != 0 && !id.equals(null)) { try { @@ -101,7 +101,7 @@ public User findById(Long id) throws ConditionsNotMetException { } } - public Collection getFriends(Long id) throws NotFoundException { + public Collection getFriends(Long id) { return List.of(); } @@ -152,7 +152,7 @@ private void duplicateCheck(User user) throws DuplicatedDataException { } } - public User update(@Valid User newUser) throws NotFoundException, DuplicatedDataException, ValidationException { + public User update(@Valid User newUser) throws DuplicatedDataException, ValidationException { log.info("Обработка Update-запроса..."); // Проверка на наличие ID From 34fb7e69c8051c3088ec5af0827136ee4253ccd6 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 15:35:22 +0500 Subject: [PATCH 035/118] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/controller/FilmController.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index e1f4251..5a8a8d7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -6,8 +6,6 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; -import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; -import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmRequest; From 8587e4d48c691d44b3f5887394747486ddf13c07 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 16:11:58 +0500 Subject: [PATCH 036/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B9=20=D0=BF=D0=B0=D1=80=D1=81?= =?UTF-8?q?=D0=B8=D0=BD=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 98 +++++++++---------- 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 5a8a8d7..ea41e08 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,6 +1,5 @@ package ru.yandex.practicum.filmorate.controller; -import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -13,17 +12,13 @@ import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.LinkedHashSet; +import java.util.List; @RestController @RequestMapping("/films") public class FilmController { - private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - private static final String DEFAULT_GENRE = "нет жанра"; - private final FilmStorage filmStorage; private final UserStorage userStorage; private final FilmInterface filmInterface; @@ -39,81 +34,82 @@ public FilmController( this.filmInterface = filmInterface; } + /** + * Получить список всех фильмов. + * + * @return список всех фильмов + */ @GetMapping public List findAll() { return filmStorage.findAll(); } + /** + * Получить фильм по его идентификатору. + * + * @param id идентификатор фильма + * @return объект фильма + */ @GetMapping("/{id}") public FilmRequest findById(@PathVariable("id") Long id) { return filmStorage.findById(id); } + /** + * Создать новый фильм. + * + * @param buffer объект запроса с данными фильма + * @return созданный фильм + */ @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmRequest create(@Valid @RequestBody ObjectNode objectNode) { - Buffer buffer = parseObjectNodeToBuffer(objectNode); + public FilmRequest create(@Valid @RequestBody Buffer buffer) { return filmStorage.create(buffer); } + /** + * Обновить данные фильма. + * + * @param buffer объект запроса с новыми данными фильма + * @return обновленный фильм + */ @PutMapping - public FilmRequest update(@Valid @RequestBody ObjectNode objectNode) { - Buffer buffer = parseObjectNodeToBuffer(objectNode); + public FilmRequest update(@Valid @RequestBody Buffer buffer) { return filmStorage.update(buffer); } + /** + * Добавить лайк фильму от пользователя. + * + * @param id идентификатор фильма + * @param userId идентификатор пользователя + * @return фильм с обновленным списком лайков + */ @PutMapping("/{id}/like/{userId}") public FilmRequest addLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { return filmInterface.addLike(userId, id); } - @DeleteMapping("/{id}/like/{userId}") - public FilmRequest delLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { - return filmInterface.delLike(userId, id); - } - - @GetMapping("/popular") - public LinkedHashSet viewRating(@RequestParam(required = false) Long count) { - return filmInterface.viewRating(count); - } - /** - * преобразует json объект в объект Buffer + * Удалить лайк у фильма от пользователя. * - * @param objectNode json объект - * @return объект Buffer + * @param id идентификатор фильма + * @param userId идентификатор пользователя + * @return фильм с обновленным списком лайков */ - private Buffer parseObjectNodeToBuffer(ObjectNode objectNode) { - Long id = objectNode.has("id") ? objectNode.get("id").asLong() : 0L; - String name = objectNode.get("name").asText(); - String description = objectNode.get("description").asText(); - String releaseDate = objectNode.get("releaseDate").asText(); - Integer duration = objectNode.get("duration").asInt(); - List mpa = objectNode.get("mpa").findValuesAsText("id"); - List genres = extractGenresFromObjectNode(objectNode); - - return Buffer.of( - id, - name, - description, - LocalDate.parse(releaseDate, DATE_FORMATTER), - duration, - genres, - Long.valueOf(mpa.get(0)) - ); + @DeleteMapping("/{id}/like/{userId}") + public FilmRequest delLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { + return filmInterface.delLike(userId, id); } /** - * извлекает список жанров из json объекта + * Получить список самых популярных фильмов. * - * @param objectNode json объект - * @return список жанров + * @param count количество фильмов (необязательный параметр) + * @return список фильмов, отсортированных по популярности */ - private List extractGenresFromObjectNode(ObjectNode objectNode) { - try { - return objectNode.get("genres").findValuesAsText("id"); - } catch (NullPointerException e) { - return List.of(DEFAULT_GENRE); - } + @GetMapping("/popular") + public LinkedHashSet viewRating(@RequestParam(required = false) Long count) { + return filmInterface.viewRating(count); } } \ No newline at end of file From 61fcc05978af1d92273d8732599b665f5418aca4 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 16:21:06 +0500 Subject: [PATCH 037/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?mpa=20constant?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 98 ++++++++++--------- .../filmorate/model/MpaConstant.java | 26 ++--- .../filmorate/service/FilmService.java | 10 +- 3 files changed, 69 insertions(+), 65 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index ea41e08..5a8a8d7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.controller; +import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -12,13 +13,17 @@ import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.util.LinkedHashSet; -import java.util.List; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.*; @RestController @RequestMapping("/films") public class FilmController { + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static final String DEFAULT_GENRE = "нет жанра"; + private final FilmStorage filmStorage; private final UserStorage userStorage; private final FilmInterface filmInterface; @@ -34,82 +39,81 @@ public FilmController( this.filmInterface = filmInterface; } - /** - * Получить список всех фильмов. - * - * @return список всех фильмов - */ @GetMapping public List findAll() { return filmStorage.findAll(); } - /** - * Получить фильм по его идентификатору. - * - * @param id идентификатор фильма - * @return объект фильма - */ @GetMapping("/{id}") public FilmRequest findById(@PathVariable("id") Long id) { return filmStorage.findById(id); } - /** - * Создать новый фильм. - * - * @param buffer объект запроса с данными фильма - * @return созданный фильм - */ @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmRequest create(@Valid @RequestBody Buffer buffer) { + public FilmRequest create(@Valid @RequestBody ObjectNode objectNode) { + Buffer buffer = parseObjectNodeToBuffer(objectNode); return filmStorage.create(buffer); } - /** - * Обновить данные фильма. - * - * @param buffer объект запроса с новыми данными фильма - * @return обновленный фильм - */ @PutMapping - public FilmRequest update(@Valid @RequestBody Buffer buffer) { + public FilmRequest update(@Valid @RequestBody ObjectNode objectNode) { + Buffer buffer = parseObjectNodeToBuffer(objectNode); return filmStorage.update(buffer); } - /** - * Добавить лайк фильму от пользователя. - * - * @param id идентификатор фильма - * @param userId идентификатор пользователя - * @return фильм с обновленным списком лайков - */ @PutMapping("/{id}/like/{userId}") public FilmRequest addLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { return filmInterface.addLike(userId, id); } - /** - * Удалить лайк у фильма от пользователя. - * - * @param id идентификатор фильма - * @param userId идентификатор пользователя - * @return фильм с обновленным списком лайков - */ @DeleteMapping("/{id}/like/{userId}") public FilmRequest delLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { return filmInterface.delLike(userId, id); } - /** - * Получить список самых популярных фильмов. - * - * @param count количество фильмов (необязательный параметр) - * @return список фильмов, отсортированных по популярности - */ @GetMapping("/popular") public LinkedHashSet viewRating(@RequestParam(required = false) Long count) { return filmInterface.viewRating(count); } + + /** + * преобразует json объект в объект Buffer + * + * @param objectNode json объект + * @return объект Buffer + */ + private Buffer parseObjectNodeToBuffer(ObjectNode objectNode) { + Long id = objectNode.has("id") ? objectNode.get("id").asLong() : 0L; + String name = objectNode.get("name").asText(); + String description = objectNode.get("description").asText(); + String releaseDate = objectNode.get("releaseDate").asText(); + Integer duration = objectNode.get("duration").asInt(); + List mpa = objectNode.get("mpa").findValuesAsText("id"); + List genres = extractGenresFromObjectNode(objectNode); + + return Buffer.of( + id, + name, + description, + LocalDate.parse(releaseDate, DATE_FORMATTER), + duration, + genres, + Long.valueOf(mpa.get(0)) + ); + } + + /** + * извлекает список жанров из json объекта + * + * @param objectNode json объект + * @return список жанров + */ + private List extractGenresFromObjectNode(ObjectNode objectNode) { + try { + return objectNode.get("genres").findValuesAsText("id"); + } catch (NullPointerException e) { + return List.of(DEFAULT_GENRE); + } + } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/MpaConstant.java b/src/main/java/ru/yandex/practicum/filmorate/model/MpaConstant.java index e045398..d79e8f4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/MpaConstant.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/MpaConstant.java @@ -1,13 +1,13 @@ -package ru.yandex.practicum.filmorate.model; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; - -@Data -@EqualsAndHashCode(of = {"id"}) -@AllArgsConstructor(staticName = "of") -public class MpaConstant { - private Long id; - private String name; -} \ No newline at end of file +//package ru.yandex.practicum.filmorate.model; +// +//import lombok.AllArgsConstructor; +//import lombok.Data; +//import lombok.EqualsAndHashCode; +// +//@Data +//@EqualsAndHashCode(of = {"id"}) +//@AllArgsConstructor(staticName = "of") +//public class MpaConstant { +// private Long id; +// private String name; +//} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index b054c0b..8d6a897 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -150,12 +150,12 @@ public GenreConstant viewGenreName(Long id) { } else return GenreConstant.of(id, genre.get(id)); } - public List viewFilmsRating() { + public List viewFilmsRating() { log.info("Обработка Get-запроса..."); Map genre = jdbcTemplate.query(sqlQuery8, new RatingNameExtractor()); - List mpaConstant = new ArrayList<>(); + List mpaConstant = new ArrayList<>(); for (Long l : genre.keySet()) - mpaConstant.add(MpaConstant.of(l, genre.get(l))); + mpaConstant.add(Mpa.of(l, genre.get(l))); return mpaConstant; } @@ -172,12 +172,12 @@ public Map extractData(ResultSet rs) throws SQLException { } } - public MpaConstant viewRatingName(Long id) { + public Mpa viewRatingName(Long id) { log.info("Обработка Get-запроса..."); Map genre = jdbcTemplate.query(sqlQuery9, new RatingNameExtractor(), id); if (id < 0 || id > 6) { log.error("Exception", new NotFoundException("NULL", "Рейтинг с указанным идентификатором не существует.")); throw new NotFoundException("NULL", "Рейтинг с указанным идентификатором не существует."); - } else return MpaConstant.of(id, genre.get(id)); + } else return Mpa.of(id, genre.get(id)); } } \ No newline at end of file From a99c72bd64a6b6aa1bf22dedf5ae3f38015293e1 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 16:51:34 +0500 Subject: [PATCH 038/118] =?UTF-8?q?notfoundexception=20=D0=B8=20=D0=BD?= =?UTF-8?q?=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B7=D0=B0=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/NotFoundException.java | 2 +- .../yandex/practicum/filmorate/model/Mpa.java | 4 +- .../filmorate/model/MpaConstant.java | 13 ----- .../filmorate/service/FilmService.java | 55 ++++++++++--------- .../filmorate/service/UserService.java | 4 +- .../filmorate/storage/film/FilmDbStorage.java | 4 +- .../storage/genre/GenreDbStorage.java | 2 +- .../filmorate/storage/mpa/MpaDbStorage.java | 2 +- .../filmorate/storage/user/UserDbStorage.java | 6 +- 9 files changed, 40 insertions(+), 52 deletions(-) delete mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/MpaConstant.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java index 9348778..82e3f72 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java @@ -1,7 +1,7 @@ package ru.yandex.practicum.filmorate.exception; public class NotFoundException extends RuntimeException { - public NotFoundException(String message, String s) { + public NotFoundException(String message) { super(message); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java index b2f95c9..35e715a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java @@ -8,6 +8,6 @@ @EqualsAndHashCode(of = {"id"}) @AllArgsConstructor(staticName = "of") public class Mpa { - Long id; - String name; + private Long id; + private String name; } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/MpaConstant.java b/src/main/java/ru/yandex/practicum/filmorate/model/MpaConstant.java deleted file mode 100644 index d79e8f4..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/model/MpaConstant.java +++ /dev/null @@ -1,13 +0,0 @@ -//package ru.yandex.practicum.filmorate.model; -// -//import lombok.AllArgsConstructor; -//import lombok.Data; -//import lombok.EqualsAndHashCode; -// -//@Data -//@EqualsAndHashCode(of = {"id"}) -//@AllArgsConstructor(staticName = "of") -//public class MpaConstant { -// private Long id; -// private String name; -//} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 8d6a897..bd8502c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -29,15 +29,16 @@ public class FilmService implements FilmInterface { FilmStorage filmStorage; private final JdbcTemplate jdbcTemplate; - private final String sqlQuery1 = "select filmId, userId from likedUsers"; - private final String sqlQuery2 = "insert into likedUsers(filmId, userId) " + "values (?, ?)"; - private final String sqlQuery3 = "select filmId, genreId from filmGenre where filmId = ?"; - private final String sqlQuery4 = "delete from likedUsers where filmId = ? and userId = ?"; - private final String sqlQuery5 = "select f.id as name, COUNT(l.userId) as coun from likedUsers as l LEFT OUTER JOIN film AS f ON l.filmId = f.id GROUP BY f.name ORDER BY COUNT(l.userId) DESC LIMIT 10"; - private final String sqlQuery6 = "select id, name from genre"; - private final String sqlQuery7 = "select id, name from genre where id = ?"; - private final String sqlQuery8 = "select id, rating from filmrating"; - private final String sqlQuery9 = "select id, rating from filmrating where id = ?"; + // SQL-запросы + private final String selectLikedUsersQuery = "select filmId, userId from likedUsers"; + private final String insertLikeQuery = "insert into likedUsers(filmId, userId) values (?, ?)"; + private final String selectFilmGenresQuery = "select filmId, genreId from filmGenre where filmId = ?"; + private final String deleteLikeQuery = "delete from likedUsers where filmId = ? and userId = ?"; + private final String selectTopFilmsQuery = "select f.id as name, COUNT(l.userId) as coun from likedUsers as l LEFT OUTER JOIN film AS f ON l.filmId = f.id GROUP BY f.name ORDER BY COUNT(l.userId) DESC LIMIT 10"; + private final String selectAllGenresQuery = "select id, name from genre"; + private final String selectGenreByIdQuery = "select id, name from genre where id = ?"; + private final String selectAllRatingsQuery = "select id, rating from filmrating"; + private final String selectRatingByIdQuery = "select id, rating from filmrating where id = ?"; public static class TopLikedUsersExtractor implements ResultSetExtractor> { @Override @@ -56,17 +57,17 @@ public LinkedHashMap extractData(ResultSet rs) throws SQLException { public FilmRequest addLike(Long idUser, Long idFilm) { log.info("Обработка Post-запроса..."); if (userStorage.findById(idUser) != null && filmStorage.findById(idFilm) != null) { - Map> likedUsers = jdbcTemplate.query(sqlQuery1, new FilmDbStorage.LikedUsersExtractor()); + Map> likedUsers = jdbcTemplate.query(selectLikedUsersQuery, new FilmDbStorage.LikedUsersExtractor()); if (likedUsers.get(idFilm) != null && likedUsers.get(idFilm).contains(idUser)) { log.error("Exception", new ConditionsNotMetException(idUser.toString())); throw new ConditionsNotMetException(idUser.toString()); } else { - jdbcTemplate.update(sqlQuery2, idFilm, idUser); + jdbcTemplate.update(insertLikeQuery, idFilm, idUser); } } FilmRequest film = filmStorage.findById(idFilm); LinkedHashSet genres = new LinkedHashSet<>(); - Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmDbStorage.FilmGenreExtractor(), film.getId()); + Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), film.getId()); if (!filmGenre.isEmpty()) { for (Long g : filmGenre.get(film.getId())) genres.add(g); @@ -78,15 +79,15 @@ public FilmRequest addLike(Long idUser, Long idFilm) { public FilmRequest delLike(Long idUser, Long idFilm) { log.info("Обработка Del-запроса..."); if (userStorage.findById(idUser) != null && filmStorage.findById(idFilm) != null) { - Map> likedUsers = jdbcTemplate.query(sqlQuery1, new FilmDbStorage.LikedUsersExtractor()); + Map> likedUsers = jdbcTemplate.query(selectLikedUsersQuery, new FilmDbStorage.LikedUsersExtractor()); if (likedUsers.get(idFilm) != null && !likedUsers.get(idFilm).contains(idUser)) { log.error("Exception", new ConditionsNotMetException(idUser.toString())); throw new ConditionsNotMetException(idUser.toString()); - } else jdbcTemplate.update(sqlQuery4, idFilm, idUser); + } else jdbcTemplate.update(deleteLikeQuery, idFilm, idUser); } FilmRequest film = filmStorage.findById(idFilm); LinkedHashSet genres = new LinkedHashSet<>(); - Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmDbStorage.FilmGenreExtractor(), film.getId()); + Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), film.getId()); if (!filmGenre.isEmpty()) { for (Long g : filmGenre.get(film.getId())) genres.add(g); @@ -100,15 +101,15 @@ public List viewRaiting(Long count) { public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); - LinkedHashMap likedUsers = jdbcTemplate.query(sqlQuery5, new TopLikedUsersExtractor()); + LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); LinkedHashSet films = new LinkedHashSet<>(); if (likedUsers == null) { - log.error("Exception", new NotFoundException(count.toString(), "Список фильмов с рейтингом пуст.")); - throw new NotFoundException(count.toString(), "Список фильмов с рейтингом пуст."); + log.error("Exception", new NotFoundException("Список фильмов с рейтингом пуст.")); + throw new NotFoundException("Список фильмов с рейтингом пуст."); } else { LinkedHashSet genres = new LinkedHashSet<>(); for (Long l : likedUsers.keySet()) { - Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); + Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); if (!filmGenre.isEmpty()) { for (Long g : filmGenre.get(filmStorage.findById(l).getId())) genres.add(g); @@ -121,7 +122,7 @@ public LinkedHashSet viewRating(Long count) { public List viewGenre() { log.info("Обработка Get-запроса..."); - Map genre = jdbcTemplate.query(sqlQuery6, new GenreExtractor()); + Map genre = jdbcTemplate.query(selectAllGenresQuery, new GenreExtractor()); List genreConstant = new ArrayList<>(); for (Long l : genre.keySet()) genreConstant.add(GenreConstant.of(l, genre.get(l))); @@ -143,16 +144,16 @@ public Map extractData(ResultSet rs) throws SQLException { public GenreConstant viewGenreName(Long id) { log.info("Обработка Get-запроса..."); - Map genre = jdbcTemplate.query(sqlQuery7, new GenreExtractor(), id); + Map genre = jdbcTemplate.query(selectGenreByIdQuery, new GenreExtractor(), id); if (id < 0 || id > 7) { - log.error("Exception", new NotFoundException("NULL", "Жанра с указанным идентификатором не существует.")); - throw new NotFoundException("NULL", "Жанра с указанным идентификатором не существует."); + log.error("Exception", new NotFoundException("Жанра с указанным идентификатором не существует.")); + throw new NotFoundException("Жанра с указанным идентификатором не существует."); } else return GenreConstant.of(id, genre.get(id)); } public List viewFilmsRating() { log.info("Обработка Get-запроса..."); - Map genre = jdbcTemplate.query(sqlQuery8, new RatingNameExtractor()); + Map genre = jdbcTemplate.query(selectAllRatingsQuery, new RatingNameExtractor()); List mpaConstant = new ArrayList<>(); for (Long l : genre.keySet()) mpaConstant.add(Mpa.of(l, genre.get(l))); @@ -174,10 +175,10 @@ public Map extractData(ResultSet rs) throws SQLException { public Mpa viewRatingName(Long id) { log.info("Обработка Get-запроса..."); - Map genre = jdbcTemplate.query(sqlQuery9, new RatingNameExtractor(), id); + Map genre = jdbcTemplate.query(selectRatingByIdQuery, new RatingNameExtractor(), id); if (id < 0 || id > 6) { - log.error("Exception", new NotFoundException("NULL", "Рейтинг с указанным идентификатором не существует.")); - throw new NotFoundException("NULL", "Рейтинг с указанным идентификатором не существует."); + log.error("Exception", new NotFoundException("Рейтинг с указанным идентификатором не существует.")); + throw new NotFoundException("Рейтинг с указанным идентификатором не существует."); } else return Mpa.of(id, genre.get(id)); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 2415f3f..9de28d2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -122,7 +122,7 @@ private void logAndThrowConditionsNotMetException(String message) { } private void logAndThrowNotFoundException(String value) { - log.error("Exception", new NotFoundException(value, UserService.ERROR_USER_NOT_FOUND)); - throw new NotFoundException(value, UserService.ERROR_USER_NOT_FOUND); + log.error("Exception", new NotFoundException(UserService.ERROR_USER_NOT_FOUND)); + throw new NotFoundException(UserService.ERROR_USER_NOT_FOUND); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 71e3f33..7a94c7d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -262,7 +262,7 @@ private void logAndThrowConditionsNotMetException(String message) { } private void logAndThrowNotFoundException(String value, String message) { - log.error("Exception", new NotFoundException(value, message)); - throw new NotFoundException(value, message); + log.error("Exception", new NotFoundException(message)); + throw new NotFoundException(message); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/genre/GenreDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/genre/GenreDbStorage.java index ab4d25f..03f756a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/genre/GenreDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/genre/GenreDbStorage.java @@ -24,7 +24,7 @@ public Genre getGenreById(Long id) { try { return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> Genre.of(rs.getLong("id"), rs.getString("name")), id); } catch (DataAccessException e) { - throw new NotFoundException(id.toString(), "Genre with id " + id + " not found"); + throw new NotFoundException("Genre with id " + id + " not found"); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/mpa/MpaDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/mpa/MpaDbStorage.java index 4b833c3..0800d79 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/mpa/MpaDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/mpa/MpaDbStorage.java @@ -24,7 +24,7 @@ public Mpa getMpaById(Long id) { try { return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> Mpa.of(rs.getLong("id"), rs.getString("rating")), id); } catch (DataAccessException e) { - throw new NotFoundException(id.toString(), "MPA with id " + id + " not found"); + throw new NotFoundException("MPA with id " + id + " not found"); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index b82d3c6..1ac412e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -87,8 +87,8 @@ public User findById(Long id) { jdbcTemplate.queryForObject(sqlQuery3, this::mapRowToUser, id); } catch (DataAccessException e) { if (e != null) { - log.error("Exception", new NotFoundException(id.toString(), "Пользователь с данным идентификатором отсутствует в базе")); - throw new NotFoundException(id.toString(), "Пользователь с данным идентификатором отсутствует в базе"); + log.error("Exception", new NotFoundException("Пользователь с данным идентификатором отсутствует в базе")); + throw new NotFoundException("Пользователь с данным идентификатором отсутствует в базе"); } } User user = jdbcTemplate.queryForObject(sqlQuery3, this::mapRowToUser, id); @@ -163,7 +163,7 @@ public User update(@Valid User newUser) throws DuplicatedDataException, Validati // Поиск существующего пользователя User oldUser = findById(newUser.getId()); if (oldUser == null) { - throw new NotFoundException("oldUser", "Пользователь с указанным id не найден"); + throw new NotFoundException("Пользователь с указанным id не найден"); } // Проверка email From 8c6a1314b046734191c6ec2cc350f2d4136130a4 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 17:21:01 +0500 Subject: [PATCH 039/118] =?UTF-8?q?=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=D0=BB?= =?UTF-8?q?=D0=B0=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/FilmService.java | 41 ------------------- .../filmorate/service/GenreExtractor.java | 21 ++++++++++ .../service/RatingNameExtractor.java | 21 ++++++++++ .../service/TopLikedUsersExtractor.java | 20 +++++++++ .../filmorate/storage/film/FilmDbStorage.java | 14 ++++--- 5 files changed, 70 insertions(+), 47 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/GenreExtractor.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/RatingNameExtractor.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/TopLikedUsersExtractor.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index bd8502c..600227b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -5,7 +5,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.stereotype.Service; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; @@ -14,8 +13,6 @@ import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.*; @Service @@ -40,18 +37,6 @@ public class FilmService implements FilmInterface { private final String selectAllRatingsQuery = "select id, rating from filmrating"; private final String selectRatingByIdQuery = "select id, rating from filmrating where id = ?"; - public static class TopLikedUsersExtractor implements ResultSetExtractor> { - @Override - public LinkedHashMap extractData(ResultSet rs) throws SQLException { - LinkedHashMap data = new LinkedHashMap<>(); - while (rs.next()) { - Long filmId = rs.getLong("name"); - Long likes = rs.getLong("coun"); - data.putIfAbsent(filmId, likes); - } - return data; - } - } @Override public FilmRequest addLike(Long idUser, Long idFilm) { @@ -129,19 +114,6 @@ public List viewGenre() { return genreConstant; } - public static class GenreExtractor implements ResultSetExtractor> { - @Override - public Map extractData(ResultSet rs) throws SQLException { - Map data = new LinkedHashMap<>(); - while (rs.next()) { - Long id = rs.getLong("id"); - String name = rs.getString("name"); - data.put(id, name); - } - return data; - } - } - public GenreConstant viewGenreName(Long id) { log.info("Обработка Get-запроса..."); Map genre = jdbcTemplate.query(selectGenreByIdQuery, new GenreExtractor(), id); @@ -160,19 +132,6 @@ public List viewFilmsRating() { return mpaConstant; } - public static class RatingNameExtractor implements ResultSetExtractor> { - @Override - public Map extractData(ResultSet rs) throws SQLException { - Map data = new HashMap<>(); - while (rs.next()) { - Long id = rs.getLong("id"); - String rating = rs.getString("rating"); - data.put(id, rating); - } - return data; - } - } - public Mpa viewRatingName(Long id) { log.info("Обработка Get-запроса..."); Map genre = jdbcTemplate.query(selectRatingByIdQuery, new RatingNameExtractor(), id); diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/GenreExtractor.java b/src/main/java/ru/yandex/practicum/filmorate/service/GenreExtractor.java new file mode 100644 index 0000000..2805ca6 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/GenreExtractor.java @@ -0,0 +1,21 @@ +package ru.yandex.practicum.filmorate.service; + +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.LinkedHashMap; +import java.util.Map; + +public class GenreExtractor implements ResultSetExtractor> { + @Override + public Map extractData(ResultSet rs) throws SQLException { + Map data = new LinkedHashMap<>(); + while (rs.next()) { + Long id = rs.getLong("id"); + String name = rs.getString("name"); + data.put(id, name); + } + return data; + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/RatingNameExtractor.java b/src/main/java/ru/yandex/practicum/filmorate/service/RatingNameExtractor.java new file mode 100644 index 0000000..3e37198 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/RatingNameExtractor.java @@ -0,0 +1,21 @@ +package ru.yandex.practicum.filmorate.service; + +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +public class RatingNameExtractor implements ResultSetExtractor> { + @Override + public Map extractData(ResultSet rs) throws SQLException { + Map data = new HashMap<>(); + while (rs.next()) { + Long id = rs.getLong("id"); + String rating = rs.getString("rating"); + data.put(id, rating); + } + return data; + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/TopLikedUsersExtractor.java b/src/main/java/ru/yandex/practicum/filmorate/service/TopLikedUsersExtractor.java new file mode 100644 index 0000000..b2d79a7 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/TopLikedUsersExtractor.java @@ -0,0 +1,20 @@ +package ru.yandex.practicum.filmorate.service; + +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.LinkedHashMap; + +public class TopLikedUsersExtractor implements ResultSetExtractor> { + @Override + public LinkedHashMap extractData(ResultSet rs) throws SQLException { + LinkedHashMap data = new LinkedHashMap<>(); + while (rs.next()) { + Long filmId = rs.getLong("name"); + Long likes = rs.getLong("coun"); + data.putIfAbsent(filmId, likes); + } + return data; + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 7a94c7d..f8fef0f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -15,6 +15,8 @@ import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.*; import ru.yandex.practicum.filmorate.service.FilmService; +import ru.yandex.practicum.filmorate.service.GenreExtractor; +import ru.yandex.practicum.filmorate.service.RatingNameExtractor; import java.sql.ResultSet; import java.sql.SQLException; @@ -152,8 +154,8 @@ public FilmRequest findById(Long id) { film.setLikedUsers(likedUsers.get(id)); assert filmGenre != null; film.setGenres(filmGenre.get(id)); - Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new FilmService.RatingNameExtractor()); + Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); + Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); LinkedHashSet genres = new LinkedHashSet<>(); if (!filmGenre.isEmpty()) { for (Long g : filmGenre.get(id)) { @@ -175,8 +177,8 @@ public FilmRequest create(@Valid Buffer buffer) { SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); Long filmId = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); - Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new FilmService.RatingNameExtractor()); + Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); + Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); LinkedHashSet genres = processGenres(buffer.getGenres(), filmId, genre); updateFilmRating(buffer.getMpa(), filmId); @@ -199,8 +201,8 @@ public FilmRequest update(@Valid Buffer newFilm) { oldFilm.setReleaseDate(newFilm.getReleaseDate()); oldFilm.setDuration(newFilm.getDuration()); - Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new FilmService.GenreExtractor()); - Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new FilmService.RatingNameExtractor()); + Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); + Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); LinkedHashSet genres = processGenres(newFilm.getGenres(), oldFilm.getId(), genre); updateFilmRating(newFilm.getMpa(), oldFilm.getId()); From 94072697fcae66a5bd8628ae6c2f3ed2d4cf282a Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 17:23:33 +0500 Subject: [PATCH 040/118] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/film/FilmDbStorage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index f8fef0f..54d5469 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -14,7 +14,6 @@ import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.*; -import ru.yandex.practicum.filmorate.service.FilmService; import ru.yandex.practicum.filmorate.service.GenreExtractor; import ru.yandex.practicum.filmorate.service.RatingNameExtractor; From e35156ad15d077f9e32666aa3066a761b3ad5955 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 17:32:44 +0500 Subject: [PATCH 041/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?assert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 54d5469..5eb3b11 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -27,7 +27,7 @@ @Slf4j(topic = "TRACE") @ConfigurationPropertiesScan @Component -@Qualifier("FilmDbStorage") +@Qualifier("filmDbStorage") public class FilmDbStorage implements FilmStorage { //SQL-запросы @@ -116,11 +116,8 @@ public List findAll() { String sqlQuery4 = "select id, ratingId from film"; Map filmRating = jdbcTemplate.query(sqlQuery4, new FilmRatingExtractor()); for (Film film : films) { - assert likedUsers != null; film.setLikedUsers(likedUsers.get(film.getId())); - assert filmGenre != null; film.setGenres(filmGenre.get(film.getId())); - assert filmRating != null; film.setMpa(filmRating.get(film.getId())); } return films; @@ -137,7 +134,7 @@ public FilmRequest findById(Long id) { try { jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); } catch (DataAccessException e) { - assert id != null; + logAndThrowNotFoundException(id.toString(), ERROR_FILM_NOT_FOUND); } @@ -148,23 +145,22 @@ public FilmRequest findById(Long id) { Map> filmGenre = jdbcTemplate.query(sqlQuery7, new FilmGenreExtractor(), id); String sqlQuery8 = "select id, ratingId from film where id = ?"; Map filmRating = jdbcTemplate.query(sqlQuery8, new FilmRatingExtractor(), id); - assert film != null; - assert likedUsers != null; + + film.setLikedUsers(likedUsers.get(id)); - assert filmGenre != null; + film.setGenres(filmGenre.get(id)); Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); LinkedHashSet genres = new LinkedHashSet<>(); if (!filmGenre.isEmpty()) { for (Long g : filmGenre.get(id)) { - assert genre != null; genres.add(Genre.of(g, genre.get(g))); } } - assert filmRating != null; + film.setMpa(filmRating.get(id)); - assert rating != null; + return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), Mpa.of(film.getMpa(), rating.get(film.getMpa())), genres); } @@ -209,7 +205,6 @@ public FilmRequest update(@Valid Buffer newFilm) { jdbcTemplate.update(SQL_UPDATE_FILM, oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), oldFilm.getMpa().getId(), oldFilm.getId()); - assert rating != null; return FilmRequest.of(oldFilm.getId(), oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), new HashSet<>(), Mpa.of(newFilm.getMpa(), rating.get(newFilm.getMpa())), genres); } From 9641c760eccd6cdca7e3ad8546bc9bda11db736f Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 17:36:39 +0500 Subject: [PATCH 042/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=BC=D0=BD=D0=BE=D0=B6=D0=B5=D1=81=D1=82=D0=B2=D0=B5=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D1=81=D0=B5=D0=BB=D0=B5=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 129 ++++++++++++------ 1 file changed, 87 insertions(+), 42 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 5eb3b11..f0181db 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -107,20 +107,48 @@ public Map extractData(ResultSet rs) throws SQLException { @Override public List findAll() { log.info(LOG_GET_REQUEST); - String sqlQuery1 = "select id, name, description, releaseDate, duration from film"; - List films = jdbcTemplate.query(sqlQuery1, this::mapRowToFilm); - String sqlQuery2 = "select filmId, userId from likedUsers"; - Map> likedUsers = jdbcTemplate.query(sqlQuery2, new LikedUsersExtractor()); - String sqlQuery3 = "select filmId, genreId from filmGenre"; - Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmGenreExtractor()); - String sqlQuery4 = "select id, ratingId from film"; - Map filmRating = jdbcTemplate.query(sqlQuery4, new FilmRatingExtractor()); - for (Film film : films) { - film.setLikedUsers(likedUsers.get(film.getId())); - film.setGenres(filmGenre.get(film.getId())); - film.setMpa(filmRating.get(film.getId())); - } - return films; + String sqlQuery = """ + SELECT f.id AS filmId, f.name, f.description, f.releaseDate, f.duration, + l.userId AS likedUserId, g.genreId, r.ratingId + FROM film f + LEFT JOIN likedUsers l ON f.id = l.filmId + LEFT JOIN filmGenre g ON f.id = g.filmId + LEFT JOIN filmrating r ON f.ratingId = r.id + """; + + return jdbcTemplate.query(sqlQuery, rs -> { + Map films = new LinkedHashMap<>(); + while (rs.next()) { + Long filmId = rs.getLong("filmId"); + Film film = films.get(filmId); + if (film == null) { + film = Film.builder() + .id(filmId) + .name(rs.getString("name")) + .description(rs.getString("description")) + .releaseDate(rs.getDate("releaseDate").toLocalDate()) + .duration(rs.getInt("duration")) + .likedUsers(new HashSet<>()) + .genres(new LinkedHashSet<>()) + .mpa(rs.getLong("ratingId")) + .build(); + films.put(filmId, film); + } + + // Добавляем лайки + Long likedUserId = rs.getLong("likedUserId"); + if (likedUserId != 0) { + film.getLikedUsers().add(likedUserId); + } + + // Добавляем жанры + Long genreId = rs.getLong("genreId"); + if (genreId != 0) { + film.getGenres().add(genreId); + } + } + return new ArrayList<>(films.values()); + }); } @Override @@ -130,38 +158,55 @@ public FilmRequest findById(Long id) { logAndThrowConditionsNotMetException(ERROR_NULL_ID); } - String sqlQuery5 = "select id, name, description, releaseDate, duration from film where id = ?"; - try { - jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); - } catch (DataAccessException e) { - - logAndThrowNotFoundException(id.toString(), ERROR_FILM_NOT_FOUND); - } - - Film film = jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); - String sqlQuery6 = "select filmId, userId from likedUsers where filmId = ?"; - Map> likedUsers = jdbcTemplate.query(sqlQuery6, new LikedUsersExtractor(), id); - String sqlQuery7 = "select filmId, genreId from filmGenre where filmId = ?"; - Map> filmGenre = jdbcTemplate.query(sqlQuery7, new FilmGenreExtractor(), id); - String sqlQuery8 = "select id, ratingId from film where id = ?"; - Map filmRating = jdbcTemplate.query(sqlQuery8, new FilmRatingExtractor(), id); + String sqlQuery = """ + SELECT f.id AS filmId, f.name, f.description, f.releaseDate, f.duration, + l.userId AS likedUserId, g.genreId, r.ratingId, r.rating + FROM film f + LEFT JOIN likedUsers l ON f.id = l.filmId + LEFT JOIN filmGenre g ON f.id = g.filmId + LEFT JOIN filmrating r ON f.ratingId = r.id + WHERE f.id = ? + """; + + return jdbcTemplate.query(sqlQuery, rs -> { + FilmRequest filmRequest = null; + Set likedUsers = new HashSet<>(); + LinkedHashSet genres = new LinkedHashSet<>(); + Mpa mpa = null; - - film.setLikedUsers(likedUsers.get(id)); - - film.setGenres(filmGenre.get(id)); - Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); - Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); - LinkedHashSet genres = new LinkedHashSet<>(); - if (!filmGenre.isEmpty()) { - for (Long g : filmGenre.get(id)) { - genres.add(Genre.of(g, genre.get(g))); + while (rs.next()) { + if (filmRequest == null) { + filmRequest = FilmRequest.builder() + .id(rs.getLong("filmId")) + .name(rs.getString("name")) + .description(rs.getString("description")) + .releaseDate(rs.getDate("releaseDate").toLocalDate()) + .duration(rs.getInt("duration")) + .mpa(Mpa.of(rs.getLong("ratingId"), rs.getString("rating"))) + .build(); + } + + // Добавляем лайки + Long likedUserId = rs.getLong("likedUserId"); + if (likedUserId != 0) { + likedUsers.add(likedUserId); + } + + // Добавляем жанры + Long genreId = rs.getLong("genreId"); + if (genreId != 0) { + genres.add(Genre.of(genreId, rs.getString("genreName"))); + } } - } - film.setMpa(filmRating.get(id)); + if (filmRequest == null) { + logAndThrowNotFoundException(id.toString(), ERROR_FILM_NOT_FOUND); + } - return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), Mpa.of(film.getMpa(), rating.get(film.getMpa())), genres); + filmRequest.setLikedUsers(likedUsers); + filmRequest.setGenres(genres); + return filmRequest; + }, id); } @Override From 2e335ddc48d7b4e0360cb99e8ffe20b7ea8602fc Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 17:40:48 +0500 Subject: [PATCH 043/118] =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=D0=B0=20=D0=BA=D0=BE=D0=BD=D1=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/film/FilmDbStorage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index f0181db..1d86acc 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -27,7 +27,7 @@ @Slf4j(topic = "TRACE") @ConfigurationPropertiesScan @Component -@Qualifier("filmDbStorage") +@Qualifier("FilmDbStorage") public class FilmDbStorage implements FilmStorage { //SQL-запросы From cdd107d0c25ec2c8cfb01e8b904624d37db01d31 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 17:42:47 +0500 Subject: [PATCH 044/118] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 1d86acc..cb3b62d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -5,7 +5,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationPropertiesScan; -import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; @@ -108,13 +107,13 @@ public Map extractData(ResultSet rs) throws SQLException { public List findAll() { log.info(LOG_GET_REQUEST); String sqlQuery = """ - SELECT f.id AS filmId, f.name, f.description, f.releaseDate, f.duration, - l.userId AS likedUserId, g.genreId, r.ratingId - FROM film f - LEFT JOIN likedUsers l ON f.id = l.filmId - LEFT JOIN filmGenre g ON f.id = g.filmId - LEFT JOIN filmrating r ON f.ratingId = r.id - """; + SELECT f.id AS filmId, f.name, f.description, f.releaseDate, f.duration,\s + l.userId AS likedUserId, g.genreId, r.ratingId + FROM film f + LEFT JOIN likedUsers l ON f.id = l.filmId + LEFT JOIN filmGenre g ON f.id = g.filmId + LEFT JOIN filmrating r ON f.ratingId = r.id + \s"""; return jdbcTemplate.query(sqlQuery, rs -> { Map films = new LinkedHashMap<>(); @@ -159,14 +158,14 @@ public FilmRequest findById(Long id) { } String sqlQuery = """ - SELECT f.id AS filmId, f.name, f.description, f.releaseDate, f.duration, - l.userId AS likedUserId, g.genreId, r.ratingId, r.rating - FROM film f - LEFT JOIN likedUsers l ON f.id = l.filmId - LEFT JOIN filmGenre g ON f.id = g.filmId - LEFT JOIN filmrating r ON f.ratingId = r.id - WHERE f.id = ? - """; + SELECT f.id AS filmId, f.name, f.description, f.releaseDate, f.duration,\s + l.userId AS likedUserId, g.genreId, r.ratingId, r.rating + FROM film f + LEFT JOIN likedUsers l ON f.id = l.filmId + LEFT JOIN filmGenre g ON f.id = g.filmId + LEFT JOIN filmrating r ON f.ratingId = r.id + WHERE f.id = ? + \s"""; return jdbcTemplate.query(sqlQuery, rs -> { FilmRequest filmRequest = null; From 8e2ef28b6bd3cc369646df29e7a1a728ce297764 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 17:46:10 +0500 Subject: [PATCH 045/118] =?UTF-8?q?=D0=B2=D1=81=D0=B5=20=D0=B8=D0=B7=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BD=D0=B0=D0=B7=D0=B0?= =?UTF-8?q?=D0=B4,=20=D0=BF=D0=BE=D1=82=D0=BE=D0=BC=D1=83=20=D1=87=D1=82?= =?UTF-8?q?=D0=BE=20=D0=BF=D0=B0=D0=B4=D0=B0=D1=8E=D1=82=20=D1=81=20=D0=BE?= =?UTF-8?q?=D1=88=D0=B8=D0=B1=D0=BA=D0=BE=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 132 ++++++------------ 1 file changed, 44 insertions(+), 88 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index cb3b62d..5eb3b11 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; @@ -26,7 +27,7 @@ @Slf4j(topic = "TRACE") @ConfigurationPropertiesScan @Component -@Qualifier("FilmDbStorage") +@Qualifier("filmDbStorage") public class FilmDbStorage implements FilmStorage { //SQL-запросы @@ -106,48 +107,20 @@ public Map extractData(ResultSet rs) throws SQLException { @Override public List findAll() { log.info(LOG_GET_REQUEST); - String sqlQuery = """ - SELECT f.id AS filmId, f.name, f.description, f.releaseDate, f.duration,\s - l.userId AS likedUserId, g.genreId, r.ratingId - FROM film f - LEFT JOIN likedUsers l ON f.id = l.filmId - LEFT JOIN filmGenre g ON f.id = g.filmId - LEFT JOIN filmrating r ON f.ratingId = r.id - \s"""; - - return jdbcTemplate.query(sqlQuery, rs -> { - Map films = new LinkedHashMap<>(); - while (rs.next()) { - Long filmId = rs.getLong("filmId"); - Film film = films.get(filmId); - if (film == null) { - film = Film.builder() - .id(filmId) - .name(rs.getString("name")) - .description(rs.getString("description")) - .releaseDate(rs.getDate("releaseDate").toLocalDate()) - .duration(rs.getInt("duration")) - .likedUsers(new HashSet<>()) - .genres(new LinkedHashSet<>()) - .mpa(rs.getLong("ratingId")) - .build(); - films.put(filmId, film); - } - - // Добавляем лайки - Long likedUserId = rs.getLong("likedUserId"); - if (likedUserId != 0) { - film.getLikedUsers().add(likedUserId); - } - - // Добавляем жанры - Long genreId = rs.getLong("genreId"); - if (genreId != 0) { - film.getGenres().add(genreId); - } - } - return new ArrayList<>(films.values()); - }); + String sqlQuery1 = "select id, name, description, releaseDate, duration from film"; + List films = jdbcTemplate.query(sqlQuery1, this::mapRowToFilm); + String sqlQuery2 = "select filmId, userId from likedUsers"; + Map> likedUsers = jdbcTemplate.query(sqlQuery2, new LikedUsersExtractor()); + String sqlQuery3 = "select filmId, genreId from filmGenre"; + Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmGenreExtractor()); + String sqlQuery4 = "select id, ratingId from film"; + Map filmRating = jdbcTemplate.query(sqlQuery4, new FilmRatingExtractor()); + for (Film film : films) { + film.setLikedUsers(likedUsers.get(film.getId())); + film.setGenres(filmGenre.get(film.getId())); + film.setMpa(filmRating.get(film.getId())); + } + return films; } @Override @@ -157,55 +130,38 @@ public FilmRequest findById(Long id) { logAndThrowConditionsNotMetException(ERROR_NULL_ID); } - String sqlQuery = """ - SELECT f.id AS filmId, f.name, f.description, f.releaseDate, f.duration,\s - l.userId AS likedUserId, g.genreId, r.ratingId, r.rating - FROM film f - LEFT JOIN likedUsers l ON f.id = l.filmId - LEFT JOIN filmGenre g ON f.id = g.filmId - LEFT JOIN filmrating r ON f.ratingId = r.id - WHERE f.id = ? - \s"""; - - return jdbcTemplate.query(sqlQuery, rs -> { - FilmRequest filmRequest = null; - Set likedUsers = new HashSet<>(); - LinkedHashSet genres = new LinkedHashSet<>(); - Mpa mpa = null; + String sqlQuery5 = "select id, name, description, releaseDate, duration from film where id = ?"; + try { + jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); + } catch (DataAccessException e) { - while (rs.next()) { - if (filmRequest == null) { - filmRequest = FilmRequest.builder() - .id(rs.getLong("filmId")) - .name(rs.getString("name")) - .description(rs.getString("description")) - .releaseDate(rs.getDate("releaseDate").toLocalDate()) - .duration(rs.getInt("duration")) - .mpa(Mpa.of(rs.getLong("ratingId"), rs.getString("rating"))) - .build(); - } - - // Добавляем лайки - Long likedUserId = rs.getLong("likedUserId"); - if (likedUserId != 0) { - likedUsers.add(likedUserId); - } - - // Добавляем жанры - Long genreId = rs.getLong("genreId"); - if (genreId != 0) { - genres.add(Genre.of(genreId, rs.getString("genreName"))); - } - } + logAndThrowNotFoundException(id.toString(), ERROR_FILM_NOT_FOUND); + } + + Film film = jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); + String sqlQuery6 = "select filmId, userId from likedUsers where filmId = ?"; + Map> likedUsers = jdbcTemplate.query(sqlQuery6, new LikedUsersExtractor(), id); + String sqlQuery7 = "select filmId, genreId from filmGenre where filmId = ?"; + Map> filmGenre = jdbcTemplate.query(sqlQuery7, new FilmGenreExtractor(), id); + String sqlQuery8 = "select id, ratingId from film where id = ?"; + Map filmRating = jdbcTemplate.query(sqlQuery8, new FilmRatingExtractor(), id); + + + film.setLikedUsers(likedUsers.get(id)); - if (filmRequest == null) { - logAndThrowNotFoundException(id.toString(), ERROR_FILM_NOT_FOUND); + film.setGenres(filmGenre.get(id)); + Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); + Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); + LinkedHashSet genres = new LinkedHashSet<>(); + if (!filmGenre.isEmpty()) { + for (Long g : filmGenre.get(id)) { + genres.add(Genre.of(g, genre.get(g))); } + } + + film.setMpa(filmRating.get(id)); - filmRequest.setLikedUsers(likedUsers); - filmRequest.setGenres(genres); - return filmRequest; - }, id); + return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), Mpa.of(film.getMpa(), rating.get(film.getMpa())), genres); } @Override From 1e3f0477d37a096a1d20176cac558367922e3a77 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 17:49:27 +0500 Subject: [PATCH 046/118] =?UTF-8?q?=D0=B2=D1=81=D0=B5=20=D0=B8=D0=B7=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BD=D0=B0=D0=B7=D0=B0?= =?UTF-8?q?=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/film/FilmDbStorage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 5eb3b11..2394843 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -27,7 +27,7 @@ @Slf4j(topic = "TRACE") @ConfigurationPropertiesScan @Component -@Qualifier("filmDbStorage") +@Qualifier("FilmDbStorage") public class FilmDbStorage implements FilmStorage { //SQL-запросы From 57c23627719e8ed09cd3cad32da715d20006eae4 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 17:53:40 +0500 Subject: [PATCH 047/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D1=8E=D1=8E=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/storage/film/FilmDbStorage.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 2394843..6034f70 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -239,9 +239,8 @@ private LinkedHashSet processGenres(List genres, Long filmId, Map for (String genreIdStr : genres) { Long genreId = Long.parseLong(genreIdStr); - if (!(genreId > 0 && genreId < 7)) { - logAndThrowNotFoundException(genreId.toString(), ERROR_INVALID_GENRE); - } + logAndThrowNotFoundException(genreId.toString(), ERROR_INVALID_GENRE); + jdbcTemplate.update(SQL_INSERT_FILM_GENRE, filmId, genreId); result.add(Genre.of(genreId, genreMap.get(genreId))); } From 11b239e441d4356ed6e2ec110b288bcbf5796948 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 17:57:22 +0500 Subject: [PATCH 048/118] =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=BD=D0=B0=D0=B7=D0=B0=D0=B4,=20=D0=BF?= =?UTF-8?q?=D0=BE=D1=82=D0=BE=D0=BC=D1=83=20=D1=87=D1=82=D0=BE=20=D0=BE?= =?UTF-8?q?=D0=BF=D1=8F=D1=82=D1=8C=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/storage/film/FilmDbStorage.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 6034f70..2394843 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -239,8 +239,9 @@ private LinkedHashSet processGenres(List genres, Long filmId, Map for (String genreIdStr : genres) { Long genreId = Long.parseLong(genreIdStr); - logAndThrowNotFoundException(genreId.toString(), ERROR_INVALID_GENRE); - + if (!(genreId > 0 && genreId < 7)) { + logAndThrowNotFoundException(genreId.toString(), ERROR_INVALID_GENRE); + } jdbcTemplate.update(SQL_INSERT_FILM_GENRE, filmId, genreId); result.add(Genre.of(genreId, genreMap.get(genreId))); } From c9d173619763e76f90f07aade8b42c9fc56a2779 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 18:01:47 +0500 Subject: [PATCH 049/118] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=D0=B0=20foreign=20key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index c1544fe..7256b2b 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -38,7 +38,8 @@ CREATE TABLE IF NOT EXISTS friends ( id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, userId BIGINT NOT NULL, friendId BIGINT NOT NULL, - FOREIGN KEY (userId) REFERENCES users (id) + FOREIGN KEY (userId) REFERENCES users (id), + FOREIGN KEY (friendId) REFERENCES users (id) ); CREATE TABLE IF NOT EXISTS friendRequest ( From 084da278ddf92d44a0a50a69912b881fa1f6c4a8 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 18:05:01 +0500 Subject: [PATCH 050/118] =?UTF-8?q?=D0=B5=D1=89=D0=B5=20=D0=BE=D0=B4=D0=B8?= =?UTF-8?q?=D0=BD=20foreign=20key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 7256b2b..506c157 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -48,6 +48,7 @@ CREATE TABLE IF NOT EXISTS friendRequest ( friendId BIGINT NOT NULL, accept BOOLEAN, FOREIGN KEY (userId) REFERENCES users (id) + FOREIGN KEY (friendId) REFERENCES users (id) ); CREATE TABLE IF NOT EXISTS likedUsers ( From bcad0ce37e0e812a2c20c33291a53cf7e19df759 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 18:07:35 +0500 Subject: [PATCH 051/118] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D1=82=20=D0=BF?= =?UTF-8?q?=D0=BE=20=D1=82=D0=B5=D1=81=D1=82=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/schema.sql | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 506c157..7256b2b 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -48,7 +48,6 @@ CREATE TABLE IF NOT EXISTS friendRequest ( friendId BIGINT NOT NULL, accept BOOLEAN, FOREIGN KEY (userId) REFERENCES users (id) - FOREIGN KEY (friendId) REFERENCES users (id) ); CREATE TABLE IF NOT EXISTS likedUsers ( From d2fa88830a0877722c9709529923b136b7c210bd Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 21:34:13 +0500 Subject: [PATCH 052/118] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D1=8B=D0=B2=D0=B0=D1=8E=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7?= =?UTF-8?q?=20json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 131 ++++++++++++------ 1 file changed, 90 insertions(+), 41 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 2394843..dd357d2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -107,20 +107,45 @@ public Map extractData(ResultSet rs) throws SQLException { @Override public List findAll() { log.info(LOG_GET_REQUEST); - String sqlQuery1 = "select id, name, description, releaseDate, duration from film"; - List films = jdbcTemplate.query(sqlQuery1, this::mapRowToFilm); - String sqlQuery2 = "select filmId, userId from likedUsers"; - Map> likedUsers = jdbcTemplate.query(sqlQuery2, new LikedUsersExtractor()); - String sqlQuery3 = "select filmId, genreId from filmGenre"; - Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmGenreExtractor()); - String sqlQuery4 = "select id, ratingId from film"; - Map filmRating = jdbcTemplate.query(sqlQuery4, new FilmRatingExtractor()); - for (Film film : films) { - film.setLikedUsers(likedUsers.get(film.getId())); - film.setGenres(filmGenre.get(film.getId())); - film.setMpa(filmRating.get(film.getId())); - } - return films; + + String sqlQuery = "SELECT f.id AS filmId, f.name, f.description, f.releaseDate, f.duration, " + + "fg.genreId, g.name AS genreName, lu.userId AS likedUserId, fr.ratingId " + + "FROM film f " + + "LEFT JOIN filmGenre fg ON f.id = fg.filmId " + + "LEFT JOIN genre g ON fg.genreId = g.id " + + "LEFT JOIN likedUsers lu ON f.id = lu.filmId " + + "LEFT JOIN filmRating fr ON f.id = fr.filmId"; + + Map filmMap = new HashMap<>(); + jdbcTemplate.query(sqlQuery, rs -> { + Long filmId = rs.getLong("filmId"); + Film film = filmMap.get(filmId); + if (film == null) { + film = Film.builder() + .id(filmId) + .name(rs.getString("name")) + .description(rs.getString("description")) + .releaseDate(rs.getDate("releaseDate").toLocalDate()) + .duration(rs.getInt("duration")) + .likedUsers(new HashSet<>()) + .genres(new LinkedHashSet<>()) + .mpa(rs.getLong("ratingId")) + .build(); + filmMap.put(filmId, film); + } + + Long genreId = rs.getLong("genreId"); + if (genreId > 0) { + film.getGenres().add(Genre.of(genreId, rs.getString("genreName")).getId()); + } + + Long likedUserId = rs.getLong("likedUserId"); + if (likedUserId > 0) { + film.getLikedUsers().add(likedUserId); + } + }); + + return new ArrayList<>(filmMap.values()); } @Override @@ -130,38 +155,62 @@ public FilmRequest findById(Long id) { logAndThrowConditionsNotMetException(ERROR_NULL_ID); } - String sqlQuery5 = "select id, name, description, releaseDate, duration from film where id = ?"; - try { - jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); - } catch (DataAccessException e) { - - logAndThrowNotFoundException(id.toString(), ERROR_FILM_NOT_FOUND); - } - - Film film = jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); - String sqlQuery6 = "select filmId, userId from likedUsers where filmId = ?"; - Map> likedUsers = jdbcTemplate.query(sqlQuery6, new LikedUsersExtractor(), id); - String sqlQuery7 = "select filmId, genreId from filmGenre where filmId = ?"; - Map> filmGenre = jdbcTemplate.query(sqlQuery7, new FilmGenreExtractor(), id); - String sqlQuery8 = "select id, ratingId from film where id = ?"; - Map filmRating = jdbcTemplate.query(sqlQuery8, new FilmRatingExtractor(), id); - + // Основной запрос с JOIN для получения всех данных о фильме + String sqlQuery = "SELECT f.id AS filmId, f.name, f.description, f.releaseDate, f.duration, " + + "fg.genreId, g.name AS genreName, lu.userId AS likedUserId, fr.ratingId, r.rating AS ratingName " + + "FROM film f " + + "LEFT JOIN filmGenre fg ON f.id = fg.filmId " + + "LEFT JOIN genre g ON fg.genreId = g.id " + + "LEFT JOIN likedUsers lu ON f.id = lu.filmId " + + "LEFT JOIN filmRating fr ON f.id = fr.filmId " + + "LEFT JOIN filmrating r ON fr.ratingId = r.id " + + "WHERE f.id = ?"; + + // Используем ResultSetExtractor для обработки результата + FilmRequest filmRequest = jdbcTemplate.query(sqlQuery, rs -> { + FilmRequest.FilmRequestBuilder filmRequestBuilder = null; + Set likedUsers = new HashSet<>(); + LinkedHashSet genres = new LinkedHashSet<>(); + Mpa mpa = null; - film.setLikedUsers(likedUsers.get(id)); + while (rs.next()) { + if (filmRequestBuilder == null) { + // Создаем объект FilmRequest на основе данных из первой строки + filmRequestBuilder = FilmRequest.builder() + .id(rs.getLong("filmId")) + .name(rs.getString("name")) + .description(rs.getString("description")) + .releaseDate(rs.getDate("releaseDate").toLocalDate()) + .duration(rs.getInt("duration")) + .mpa(Mpa.of(rs.getLong("ratingId"), rs.getString("ratingName"))); + } + + // Собираем лайки + Long likedUserId = rs.getLong("likedUserId"); + if (likedUserId > 0) { + likedUsers.add(likedUserId); + } + + // Собираем жанры + Long genreId = rs.getLong("genreId"); + if (genreId > 0) { + genres.add(Genre.of(genreId, rs.getString("genreName"))); + } + } - film.setGenres(filmGenre.get(id)); - Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); - Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); - LinkedHashSet genres = new LinkedHashSet<>(); - if (!filmGenre.isEmpty()) { - for (Long g : filmGenre.get(id)) { - genres.add(Genre.of(g, genre.get(g))); + if (filmRequestBuilder == null) { + // Если фильм не найден, выбрасываем исключение + logAndThrowNotFoundException(id.toString(), ERROR_FILM_NOT_FOUND); } - } - film.setMpa(filmRating.get(id)); + // Устанавливаем лайки и жанры + return filmRequestBuilder + .likedUsers(likedUsers) + .genres(genres) + .build(); + }, id); - return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), Mpa.of(film.getMpa(), rating.get(film.getMpa())), genres); + return filmRequest; } @Override From 5b6aaeccb0e2d2c2c4af05cc81411552c85ff356 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 21:36:53 +0500 Subject: [PATCH 053/118] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/film/FilmDbStorage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index dd357d2..5072685 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -5,7 +5,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationPropertiesScan; -import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; From ffc8e2b9b78b5e2e190d7b7b4b3f20443ce4f580 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 21:45:19 +0500 Subject: [PATCH 054/118] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D1=82=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 132 ++++++------------ 1 file changed, 42 insertions(+), 90 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 5072685..2394843 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; @@ -106,45 +107,20 @@ public Map extractData(ResultSet rs) throws SQLException { @Override public List findAll() { log.info(LOG_GET_REQUEST); - - String sqlQuery = "SELECT f.id AS filmId, f.name, f.description, f.releaseDate, f.duration, " + - "fg.genreId, g.name AS genreName, lu.userId AS likedUserId, fr.ratingId " + - "FROM film f " + - "LEFT JOIN filmGenre fg ON f.id = fg.filmId " + - "LEFT JOIN genre g ON fg.genreId = g.id " + - "LEFT JOIN likedUsers lu ON f.id = lu.filmId " + - "LEFT JOIN filmRating fr ON f.id = fr.filmId"; - - Map filmMap = new HashMap<>(); - jdbcTemplate.query(sqlQuery, rs -> { - Long filmId = rs.getLong("filmId"); - Film film = filmMap.get(filmId); - if (film == null) { - film = Film.builder() - .id(filmId) - .name(rs.getString("name")) - .description(rs.getString("description")) - .releaseDate(rs.getDate("releaseDate").toLocalDate()) - .duration(rs.getInt("duration")) - .likedUsers(new HashSet<>()) - .genres(new LinkedHashSet<>()) - .mpa(rs.getLong("ratingId")) - .build(); - filmMap.put(filmId, film); - } - - Long genreId = rs.getLong("genreId"); - if (genreId > 0) { - film.getGenres().add(Genre.of(genreId, rs.getString("genreName")).getId()); - } - - Long likedUserId = rs.getLong("likedUserId"); - if (likedUserId > 0) { - film.getLikedUsers().add(likedUserId); - } - }); - - return new ArrayList<>(filmMap.values()); + String sqlQuery1 = "select id, name, description, releaseDate, duration from film"; + List films = jdbcTemplate.query(sqlQuery1, this::mapRowToFilm); + String sqlQuery2 = "select filmId, userId from likedUsers"; + Map> likedUsers = jdbcTemplate.query(sqlQuery2, new LikedUsersExtractor()); + String sqlQuery3 = "select filmId, genreId from filmGenre"; + Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmGenreExtractor()); + String sqlQuery4 = "select id, ratingId from film"; + Map filmRating = jdbcTemplate.query(sqlQuery4, new FilmRatingExtractor()); + for (Film film : films) { + film.setLikedUsers(likedUsers.get(film.getId())); + film.setGenres(filmGenre.get(film.getId())); + film.setMpa(filmRating.get(film.getId())); + } + return films; } @Override @@ -154,62 +130,38 @@ public FilmRequest findById(Long id) { logAndThrowConditionsNotMetException(ERROR_NULL_ID); } - // Основной запрос с JOIN для получения всех данных о фильме - String sqlQuery = "SELECT f.id AS filmId, f.name, f.description, f.releaseDate, f.duration, " + - "fg.genreId, g.name AS genreName, lu.userId AS likedUserId, fr.ratingId, r.rating AS ratingName " + - "FROM film f " + - "LEFT JOIN filmGenre fg ON f.id = fg.filmId " + - "LEFT JOIN genre g ON fg.genreId = g.id " + - "LEFT JOIN likedUsers lu ON f.id = lu.filmId " + - "LEFT JOIN filmRating fr ON f.id = fr.filmId " + - "LEFT JOIN filmrating r ON fr.ratingId = r.id " + - "WHERE f.id = ?"; - - // Используем ResultSetExtractor для обработки результата - FilmRequest filmRequest = jdbcTemplate.query(sqlQuery, rs -> { - FilmRequest.FilmRequestBuilder filmRequestBuilder = null; - Set likedUsers = new HashSet<>(); - LinkedHashSet genres = new LinkedHashSet<>(); - Mpa mpa = null; + String sqlQuery5 = "select id, name, description, releaseDate, duration from film where id = ?"; + try { + jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); + } catch (DataAccessException e) { + + logAndThrowNotFoundException(id.toString(), ERROR_FILM_NOT_FOUND); + } + + Film film = jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); + String sqlQuery6 = "select filmId, userId from likedUsers where filmId = ?"; + Map> likedUsers = jdbcTemplate.query(sqlQuery6, new LikedUsersExtractor(), id); + String sqlQuery7 = "select filmId, genreId from filmGenre where filmId = ?"; + Map> filmGenre = jdbcTemplate.query(sqlQuery7, new FilmGenreExtractor(), id); + String sqlQuery8 = "select id, ratingId from film where id = ?"; + Map filmRating = jdbcTemplate.query(sqlQuery8, new FilmRatingExtractor(), id); - while (rs.next()) { - if (filmRequestBuilder == null) { - // Создаем объект FilmRequest на основе данных из первой строки - filmRequestBuilder = FilmRequest.builder() - .id(rs.getLong("filmId")) - .name(rs.getString("name")) - .description(rs.getString("description")) - .releaseDate(rs.getDate("releaseDate").toLocalDate()) - .duration(rs.getInt("duration")) - .mpa(Mpa.of(rs.getLong("ratingId"), rs.getString("ratingName"))); - } - - // Собираем лайки - Long likedUserId = rs.getLong("likedUserId"); - if (likedUserId > 0) { - likedUsers.add(likedUserId); - } - - // Собираем жанры - Long genreId = rs.getLong("genreId"); - if (genreId > 0) { - genres.add(Genre.of(genreId, rs.getString("genreName"))); - } - } - if (filmRequestBuilder == null) { - // Если фильм не найден, выбрасываем исключение - logAndThrowNotFoundException(id.toString(), ERROR_FILM_NOT_FOUND); + film.setLikedUsers(likedUsers.get(id)); + + film.setGenres(filmGenre.get(id)); + Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); + Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); + LinkedHashSet genres = new LinkedHashSet<>(); + if (!filmGenre.isEmpty()) { + for (Long g : filmGenre.get(id)) { + genres.add(Genre.of(g, genre.get(g))); } + } - // Устанавливаем лайки и жанры - return filmRequestBuilder - .likedUsers(likedUsers) - .genres(genres) - .build(); - }, id); + film.setMpa(filmRating.get(id)); - return filmRequest; + return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), Mpa.of(film.getMpa(), rating.get(film.getMpa())), genres); } @Override From 4da9d03bc3f620b00fedc30475fe1ba2d21119cc Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 22:10:08 +0500 Subject: [PATCH 055/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=B0=D1=80=D1=81=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 59 ++----------------- 1 file changed, 6 insertions(+), 53 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 5a8a8d7..d1ad6b8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,6 +1,5 @@ package ru.yandex.practicum.filmorate.controller; -import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -13,17 +12,13 @@ import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.LinkedHashSet; +import java.util.List; @RestController @RequestMapping("/films") public class FilmController { - private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - private static final String DEFAULT_GENRE = "нет жанра"; - private final FilmStorage filmStorage; private final UserStorage userStorage; private final FilmInterface filmInterface; @@ -51,15 +46,13 @@ public FilmRequest findById(@PathVariable("id") Long id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmRequest create(@Valid @RequestBody ObjectNode objectNode) { - Buffer buffer = parseObjectNodeToBuffer(objectNode); - return filmStorage.create(buffer); + public FilmRequest create(@Valid @RequestBody Buffer filmRequest) { + return filmStorage.create(filmRequest); } @PutMapping - public FilmRequest update(@Valid @RequestBody ObjectNode objectNode) { - Buffer buffer = parseObjectNodeToBuffer(objectNode); - return filmStorage.update(buffer); + public FilmRequest update(@Valid @RequestBody Buffer filmRequest) { + return filmStorage.update(filmRequest); } @PutMapping("/{id}/like/{userId}") @@ -76,44 +69,4 @@ public FilmRequest delLike(@Valid @PathVariable("id") Long id, @PathVariable("us public LinkedHashSet viewRating(@RequestParam(required = false) Long count) { return filmInterface.viewRating(count); } - - /** - * преобразует json объект в объект Buffer - * - * @param objectNode json объект - * @return объект Buffer - */ - private Buffer parseObjectNodeToBuffer(ObjectNode objectNode) { - Long id = objectNode.has("id") ? objectNode.get("id").asLong() : 0L; - String name = objectNode.get("name").asText(); - String description = objectNode.get("description").asText(); - String releaseDate = objectNode.get("releaseDate").asText(); - Integer duration = objectNode.get("duration").asInt(); - List mpa = objectNode.get("mpa").findValuesAsText("id"); - List genres = extractGenresFromObjectNode(objectNode); - - return Buffer.of( - id, - name, - description, - LocalDate.parse(releaseDate, DATE_FORMATTER), - duration, - genres, - Long.valueOf(mpa.get(0)) - ); - } - - /** - * извлекает список жанров из json объекта - * - * @param objectNode json объект - * @return список жанров - */ - private List extractGenresFromObjectNode(ObjectNode objectNode) { - try { - return objectNode.get("genres").findValuesAsText("id"); - } catch (NullPointerException e) { - return List.of(DEFAULT_GENRE); - } - } } \ No newline at end of file From 3d7acc31f8c0dc9f65f746e89caa8d38f08b0ad6 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 22:17:15 +0500 Subject: [PATCH 056/118] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D1=82=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 61 ++++++++++++++++--- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index d1ad6b8..6337c40 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,24 +1,29 @@ package ru.yandex.practicum.filmorate.controller; +import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; -import ru.yandex.practicum.filmorate.model.Buffer; + import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmRequest; import ru.yandex.practicum.filmorate.service.FilmInterface; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.util.LinkedHashSet; -import java.util.List; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.*; @RestController @RequestMapping("/films") public class FilmController { + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static final String DEFAULT_GENRE = "нет жанра"; + private final FilmStorage filmStorage; private final UserStorage userStorage; private final FilmInterface filmInterface; @@ -46,13 +51,15 @@ public FilmRequest findById(@PathVariable("id") Long id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmRequest create(@Valid @RequestBody Buffer filmRequest) { - return filmStorage.create(filmRequest); + public FilmRequest create(@Valid @RequestBody ObjectNode objectNode) { + Buffer buffer = parseObjectNodeToBuffer(objectNode); + return filmStorage.create(buffer); } @PutMapping - public FilmRequest update(@Valid @RequestBody Buffer filmRequest) { - return filmStorage.update(filmRequest); + public FilmRequest update(@Valid @RequestBody ObjectNode objectNode) { + Buffer buffer = parseObjectNodeToBuffer(objectNode); + return filmStorage.update(buffer); } @PutMapping("/{id}/like/{userId}") @@ -69,4 +76,44 @@ public FilmRequest delLike(@Valid @PathVariable("id") Long id, @PathVariable("us public LinkedHashSet viewRating(@RequestParam(required = false) Long count) { return filmInterface.viewRating(count); } + + /** + * преобразует json объект в объект Buffer + * + * @param objectNode json объект + * @return объект Buffer + */ + private Buffer parseObjectNodeToBuffer(ObjectNode objectNode) { + Long id = objectNode.has("id") ? objectNode.get("id").asLong() : 0L; + String name = objectNode.get("name").asText(); + String description = objectNode.get("description").asText(); + String releaseDate = objectNode.get("releaseDate").asText(); + Integer duration = objectNode.get("duration").asInt(); + List mpa = objectNode.get("mpa").findValuesAsText("id"); + List genres = extractGenresFromObjectNode(objectNode); + + return Buffer.of( + id, + name, + description, + LocalDate.parse(releaseDate, DATE_FORMATTER), + duration, + genres, + Long.valueOf(mpa.get(0)) + ); + } + + /** + * извлекает список жанров из json объекта + * + * @param objectNode json объект + * @return список жанров + */ + private List extractGenresFromObjectNode(ObjectNode objectNode) { + try { + return objectNode.get("genres").findValuesAsText("id"); + } catch (NullPointerException e) { + return List.of(DEFAULT_GENRE); + } + } } \ No newline at end of file From fe91557a4d9564939d39adeff97e351666300f3b Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 22:19:52 +0500 Subject: [PATCH 057/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?throws?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/UserController.java | 18 ------------------ .../filmorate/storage/user/UserDbStorage.java | 6 +++--- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index 4bb6d76..f0dc671 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -44,7 +44,6 @@ public Collection findAll() { * * @param id идентификатор пользователя * @return объект пользователя - * @throws ConditionsNotMetException если идентификатор пользователя некорректен */ @GetMapping(USER_ID_PATH) public User findById(@PathVariable("id") Long id) { @@ -56,8 +55,6 @@ public User findById(@PathVariable("id") Long id) { * * @param user объект пользователя * @return созданный пользователь - * @throws ConditionsNotMetException если данные пользователя некорректны - * @throws DuplicatedDataException если email пользователя уже используется */ @PostMapping @ResponseStatus(HttpStatus.CREATED) @@ -70,9 +67,6 @@ public User create(@Valid @RequestBody User user) { * * @param newUser объект пользователя с новыми данными * @return обновленный пользователь - * @throws ConditionsNotMetException если данные пользователя некорректны - * @throws NotFoundException если пользователь с указанным id не найден - * @throws DuplicatedDataException если email пользователя уже используется */ @PutMapping public User update(@Valid @RequestBody User newUser) { @@ -85,9 +79,6 @@ public User update(@Valid @RequestBody User newUser) { * @param id идентификатор пользователя * @param friendId идентификатор друга * @return пользователь с обновленным списком друзей - * @throws ConditionsNotMetException если пользователь уже добавлен в друзья - * @throws NotFoundException если пользователь или друг не найдены - * @throws DuplicatedDataException если email пользователя уже используется */ @PutMapping(FRIEND_ID_PATH) public User addFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) { @@ -100,9 +91,6 @@ public User addFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendI * @param id идентификатор пользователя * @param friendId идентификатор друга * @return пользователь с обновленным списком друзей - * @throws ConditionsNotMetException если пользователь не найден в списке друзей - * @throws NotFoundException если пользователь или друг не найдены - * @throws DuplicatedDataException если email пользователя уже используется */ @DeleteMapping(FRIEND_ID_PATH) public User delFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendId") Long friendId) { @@ -115,9 +103,6 @@ public User delFriend(@Valid @PathVariable("id") Long id, @PathVariable("friendI * @param id идентификатор первого пользователя * @param otherId идентификатор второго пользователя * @return список общих друзей - * @throws ConditionsNotMetException если пользователи не найдены - * @throws NotFoundException если пользователи не найдены - * @throws DuplicatedDataException если email пользователя уже используется */ @GetMapping(COMMON_FRIENDS_PATH) public Set findJointFriends(@Valid @PathVariable("id") Long id, @PathVariable("otherId") Long otherId) { @@ -129,9 +114,6 @@ public Set findJointFriends(@Valid @PathVariable("id") Long id, @PathVaria * * @param id идентификатор пользователя * @return список друзей - * @throws ConditionsNotMetException если пользователь не найден - * @throws NotFoundException если пользователь не найден - * @throws DuplicatedDataException если email пользователя уже используется */ @GetMapping(FRIENDS_PATH) public Set findAllFriends(@Valid @PathVariable("id") Long id) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 1ac412e..59fc5e8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -105,7 +105,7 @@ public Collection getFriends(Long id) { return List.of(); } - public User create(@Valid User user) throws DuplicatedDataException, ValidationException { + public User create(@Valid User user) { log.info("Обработка Create-запроса..."); // Проверка на дубликат email @@ -144,7 +144,7 @@ public User create(@Valid User user) throws DuplicatedDataException, ValidationE return user; } - private void duplicateCheck(User user) throws DuplicatedDataException { + private void duplicateCheck(User user) { Set emails = jdbcTemplate.query(sqlQuery4, new EmailExtractor()); if (emails.contains(user.getEmail())) { log.error("Exception", new DuplicatedDataException("Этот имейл уже используется")); @@ -152,7 +152,7 @@ private void duplicateCheck(User user) throws DuplicatedDataException { } } - public User update(@Valid User newUser) throws DuplicatedDataException, ValidationException { + public User update(@Valid User newUser) { log.info("Обработка Update-запроса..."); // Проверка на наличие ID From 50bdf270a5001f86b1860edbaa678c9cc6f8f6e5 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 22:22:05 +0500 Subject: [PATCH 058/118] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/controller/UserController.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index f0dc671..2424ca6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -5,9 +5,6 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; -import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; -import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; -import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.service.UserInterface; import ru.yandex.practicum.filmorate.storage.user.UserStorage; From a3cc1c0d5365a6a4025f66487079b305f3aac726 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 22:23:48 +0500 Subject: [PATCH 059/118] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BC=D0=BE=D0=B4=D0=B8=D1=84=D0=B8=D0=BA?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D1=80=D1=8B=20=D0=B4=D0=BE=D1=81=D1=82=D1=83?= =?UTF-8?q?=D0=BF=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ru/yandex/practicum/filmorate/model/Genre.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java index 2d9e49c..d3914eb 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java @@ -8,6 +8,6 @@ @EqualsAndHashCode(of = {"id"}) @AllArgsConstructor(staticName = "of") public class Genre { - Long id; - String name; + private Long id; + private String name; } \ No newline at end of file From 28a9df4b502fd832387a74a008e004a1eae4dccd Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 22:29:41 +0500 Subject: [PATCH 060/118] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BB=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 14 +++++++------- .../{FilmRequest.java => FilmResponse.java} | 2 +- .../filmorate/service/FilmInterface.java | 8 ++++---- .../filmorate/service/FilmService.java | 18 +++++++++--------- .../filmorate/storage/film/FilmDbStorage.java | 14 +++++++------- .../filmorate/storage/film/FilmStorage.java | 8 ++++---- 6 files changed, 32 insertions(+), 32 deletions(-) rename src/main/java/ru/yandex/practicum/filmorate/model/{FilmRequest.java => FilmResponse.java} (96%) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 6337c40..d1c0ab6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -8,7 +8,7 @@ import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.model.FilmRequest; +import ru.yandex.practicum.filmorate.model.FilmResponse; import ru.yandex.practicum.filmorate.service.FilmInterface; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; @@ -45,35 +45,35 @@ public List findAll() { } @GetMapping("/{id}") - public FilmRequest findById(@PathVariable("id") Long id) { + public FilmResponse findById(@PathVariable("id") Long id) { return filmStorage.findById(id); } @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmRequest create(@Valid @RequestBody ObjectNode objectNode) { + public FilmResponse create(@Valid @RequestBody ObjectNode objectNode) { Buffer buffer = parseObjectNodeToBuffer(objectNode); return filmStorage.create(buffer); } @PutMapping - public FilmRequest update(@Valid @RequestBody ObjectNode objectNode) { + public FilmResponse update(@Valid @RequestBody ObjectNode objectNode) { Buffer buffer = parseObjectNodeToBuffer(objectNode); return filmStorage.update(buffer); } @PutMapping("/{id}/like/{userId}") - public FilmRequest addLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { + public FilmResponse addLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { return filmInterface.addLike(userId, id); } @DeleteMapping("/{id}/like/{userId}") - public FilmRequest delLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { + public FilmResponse delLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { return filmInterface.delLike(userId, id); } @GetMapping("/popular") - public LinkedHashSet viewRating(@RequestParam(required = false) Long count) { + public LinkedHashSet viewRating(@RequestParam(required = false) Long count) { return filmInterface.viewRating(count); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/FilmRequest.java b/src/main/java/ru/yandex/practicum/filmorate/model/FilmResponse.java similarity index 96% rename from src/main/java/ru/yandex/practicum/filmorate/model/FilmRequest.java rename to src/main/java/ru/yandex/practicum/filmorate/model/FilmResponse.java index 7ceac23..1c02cd9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/FilmRequest.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/FilmResponse.java @@ -17,7 +17,7 @@ @Builder @EqualsAndHashCode(of = {"id"}) @AllArgsConstructor(staticName = "of") -public class FilmRequest { +public class FilmResponse { private Long id; @NotNull @NotBlank diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmInterface.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmInterface.java index 57cc56a..ab6de1f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmInterface.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmInterface.java @@ -1,13 +1,13 @@ package ru.yandex.practicum.filmorate.service; -import ru.yandex.practicum.filmorate.model.FilmRequest; +import ru.yandex.practicum.filmorate.model.FilmResponse; import java.util.LinkedHashSet; public interface FilmInterface { - FilmRequest addLike(Long idUser, Long idFilm); + FilmResponse addLike(Long idUser, Long idFilm); - FilmRequest delLike(Long idUser, Long idFilm); + FilmResponse delLike(Long idUser, Long idFilm); - LinkedHashSet viewRating(Long count); + LinkedHashSet viewRating(Long count); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 600227b..2fbb810 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -39,7 +39,7 @@ public class FilmService implements FilmInterface { @Override - public FilmRequest addLike(Long idUser, Long idFilm) { + public FilmResponse addLike(Long idUser, Long idFilm) { log.info("Обработка Post-запроса..."); if (userStorage.findById(idUser) != null && filmStorage.findById(idFilm) != null) { Map> likedUsers = jdbcTemplate.query(selectLikedUsersQuery, new FilmDbStorage.LikedUsersExtractor()); @@ -50,18 +50,18 @@ public FilmRequest addLike(Long idUser, Long idFilm) { jdbcTemplate.update(insertLikeQuery, idFilm, idUser); } } - FilmRequest film = filmStorage.findById(idFilm); + FilmResponse film = filmStorage.findById(idFilm); LinkedHashSet genres = new LinkedHashSet<>(); Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), film.getId()); if (!filmGenre.isEmpty()) { for (Long g : filmGenre.get(film.getId())) genres.add(g); } - return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), film.getMpa(), genres); + return FilmResponse.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), film.getMpa(), genres); } @Override - public FilmRequest delLike(Long idUser, Long idFilm) { + public FilmResponse delLike(Long idUser, Long idFilm) { log.info("Обработка Del-запроса..."); if (userStorage.findById(idUser) != null && filmStorage.findById(idFilm) != null) { Map> likedUsers = jdbcTemplate.query(selectLikedUsersQuery, new FilmDbStorage.LikedUsersExtractor()); @@ -70,24 +70,24 @@ public FilmRequest delLike(Long idUser, Long idFilm) { throw new ConditionsNotMetException(idUser.toString()); } else jdbcTemplate.update(deleteLikeQuery, idFilm, idUser); } - FilmRequest film = filmStorage.findById(idFilm); + FilmResponse film = filmStorage.findById(idFilm); LinkedHashSet genres = new LinkedHashSet<>(); Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), film.getId()); if (!filmGenre.isEmpty()) { for (Long g : filmGenre.get(film.getId())) genres.add(g); } - return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), film.getMpa(), genres); + return FilmResponse.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), film.getMpa(), genres); } public List viewRaiting(Long count) { return List.of(); } - public LinkedHashSet viewRating(Long count) { + public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); - LinkedHashSet films = new LinkedHashSet<>(); + LinkedHashSet films = new LinkedHashSet<>(); if (likedUsers == null) { log.error("Exception", new NotFoundException("Список фильмов с рейтингом пуст.")); throw new NotFoundException("Список фильмов с рейтингом пуст."); @@ -99,7 +99,7 @@ public LinkedHashSet viewRating(Long count) { for (Long g : filmGenre.get(filmStorage.findById(l).getId())) genres.add(g); } - films.add(FilmRequest.of(filmStorage.findById(l).getId(), filmStorage.findById(l).getName(), filmStorage.findById(l).getDescription(), filmStorage.findById(l).getReleaseDate(), filmStorage.findById(l).getDuration(), new HashSet<>(), filmStorage.findById(l).getMpa(), genres)); + films.add(FilmResponse.of(filmStorage.findById(l).getId(), filmStorage.findById(l).getName(), filmStorage.findById(l).getDescription(), filmStorage.findById(l).getReleaseDate(), filmStorage.findById(l).getDuration(), new HashSet<>(), filmStorage.findById(l).getMpa(), genres)); } } return films; diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 2394843..6fd0689 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -124,7 +124,7 @@ public List findAll() { } @Override - public FilmRequest findById(Long id) { + public FilmResponse findById(Long id) { log.info(LOG_GET_REQUEST); if (id == null || id == 0) { logAndThrowConditionsNotMetException(ERROR_NULL_ID); @@ -161,11 +161,11 @@ public FilmRequest findById(Long id) { film.setMpa(filmRating.get(id)); - return FilmRequest.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), Mpa.of(film.getMpa(), rating.get(film.getMpa())), genres); + return FilmResponse.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), Mpa.of(film.getMpa(), rating.get(film.getMpa())), genres); } @Override - public FilmRequest create(@Valid Buffer buffer) { + public FilmResponse create(@Valid Buffer buffer) { log.info(LOG_CREATE_REQUEST); validateBuffer(buffer); @@ -178,17 +178,17 @@ public FilmRequest create(@Valid Buffer buffer) { LinkedHashSet genres = processGenres(buffer.getGenres(), filmId, genre); updateFilmRating(buffer.getMpa(), filmId); - return FilmRequest.of(filmId, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres); + return FilmResponse.of(filmId, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres); } @Override - public FilmRequest update(@Valid Buffer newFilm) { + public FilmResponse update(@Valid Buffer newFilm) { log.info(LOG_UPDATE_REQUEST); if (newFilm.getId() == null) { logAndThrowConditionsNotMetException("Id должен быть указан"); } - FilmRequest oldFilm = findById(newFilm.getId()); + FilmResponse oldFilm = findById(newFilm.getId()); validateBuffer(newFilm); oldFilm.setName(newFilm.getName()); @@ -205,7 +205,7 @@ public FilmRequest update(@Valid Buffer newFilm) { jdbcTemplate.update(SQL_UPDATE_FILM, oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), oldFilm.getMpa().getId(), oldFilm.getId()); - return FilmRequest.of(oldFilm.getId(), oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), + return FilmResponse.of(oldFilm.getId(), oldFilm.getName(), oldFilm.getDescription(), oldFilm.getReleaseDate(), oldFilm.getDuration(), new HashSet<>(), Mpa.of(newFilm.getMpa(), rating.get(newFilm.getMpa())), genres); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java index bfc8501..9b12145 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java @@ -2,7 +2,7 @@ import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.model.FilmRequest; +import ru.yandex.practicum.filmorate.model.FilmResponse; import java.util.List; @@ -10,9 +10,9 @@ public interface FilmStorage { List findAll(); - FilmRequest findById(Long id); + FilmResponse findById(Long id); - FilmRequest create(Buffer film); + FilmResponse create(Buffer film); - FilmRequest update(Buffer newFilm); + FilmResponse update(Buffer newFilm); } \ No newline at end of file From 1ffdbfcc8f24afc696659aa87d7b8519e65e54f9 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 22:33:49 +0500 Subject: [PATCH 061/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=83=D0=B6=D0=BD=D1=8B=D0=B5=20=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D0=BE=D0=B4=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/FilmService.java | 40 ------------------- 1 file changed, 40 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 2fbb810..6c5c7b0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -80,10 +80,6 @@ public FilmResponse delLike(Long idUser, Long idFilm) { return FilmResponse.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), film.getMpa(), genres); } - public List viewRaiting(Long count) { - return List.of(); - } - public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); @@ -104,40 +100,4 @@ public LinkedHashSet viewRating(Long count) { } return films; } - - public List viewGenre() { - log.info("Обработка Get-запроса..."); - Map genre = jdbcTemplate.query(selectAllGenresQuery, new GenreExtractor()); - List genreConstant = new ArrayList<>(); - for (Long l : genre.keySet()) - genreConstant.add(GenreConstant.of(l, genre.get(l))); - return genreConstant; - } - - public GenreConstant viewGenreName(Long id) { - log.info("Обработка Get-запроса..."); - Map genre = jdbcTemplate.query(selectGenreByIdQuery, new GenreExtractor(), id); - if (id < 0 || id > 7) { - log.error("Exception", new NotFoundException("Жанра с указанным идентификатором не существует.")); - throw new NotFoundException("Жанра с указанным идентификатором не существует."); - } else return GenreConstant.of(id, genre.get(id)); - } - - public List viewFilmsRating() { - log.info("Обработка Get-запроса..."); - Map genre = jdbcTemplate.query(selectAllRatingsQuery, new RatingNameExtractor()); - List mpaConstant = new ArrayList<>(); - for (Long l : genre.keySet()) - mpaConstant.add(Mpa.of(l, genre.get(l))); - return mpaConstant; - } - - public Mpa viewRatingName(Long id) { - log.info("Обработка Get-запроса..."); - Map genre = jdbcTemplate.query(selectRatingByIdQuery, new RatingNameExtractor(), id); - if (id < 0 || id > 6) { - log.error("Exception", new NotFoundException("Рейтинг с указанным идентификатором не существует.")); - throw new NotFoundException("Рейтинг с указанным идентификатором не существует."); - } else return Mpa.of(id, genre.get(id)); - } } \ No newline at end of file From e920739cdb8ee0b9119d24aa3d263af062153101 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 22:39:16 +0500 Subject: [PATCH 062/118] =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B0?= =?UTF-8?q?=D0=B5=D0=BC=20=D0=BE=D0=B1=D1=89=D0=B8=D1=85=20=D0=B4=D1=80?= =?UTF-8?q?=D1=83=D0=B7=D0=B5=D0=B9=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20inn?= =?UTF-8?q?er=20join?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/FilmService.java | 4 ---- .../filmorate/service/UserService.java | 17 +++++++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 6c5c7b0..9e937c0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -32,10 +32,6 @@ public class FilmService implements FilmInterface { private final String selectFilmGenresQuery = "select filmId, genreId from filmGenre where filmId = ?"; private final String deleteLikeQuery = "delete from likedUsers where filmId = ? and userId = ?"; private final String selectTopFilmsQuery = "select f.id as name, COUNT(l.userId) as coun from likedUsers as l LEFT OUTER JOIN film AS f ON l.filmId = f.id GROUP BY f.name ORDER BY COUNT(l.userId) DESC LIMIT 10"; - private final String selectAllGenresQuery = "select id, name from genre"; - private final String selectGenreByIdQuery = "select id, name from genre where id = ?"; - private final String selectAllRatingsQuery = "select id, rating from filmrating"; - private final String selectRatingByIdQuery = "select id, rating from filmrating where id = ?"; @Override diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 9de28d2..0ac9bd5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -14,6 +14,7 @@ import ru.yandex.practicum.filmorate.storage.user.UserStorage; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -73,17 +74,21 @@ public Set findJointFriends(Long idUser, Long idFriend) { validateUserExists(idUser); validateUserExists(idFriend); - Map> friends = jdbcTemplate.query(SQL_SELECT_FRIENDS, new UserDbStorage.FriendsExtractor()); - Set userFriends = friends.getOrDefault(idUser, new HashSet<>()); - Set friendFriends = friends.getOrDefault(idFriend, new HashSet<>()); + // SQL-запрос для поиска общих друзей + String sql = "SELECT f1.friend_id " + + "FROM friends f1 " + + "INNER JOIN friends f2 ON f1.friend_id = f2.friend_id " + + "WHERE f1.user_id = ? AND f2.user_id = ?"; - Set jointFriends = new HashSet<>(userFriends); - jointFriends.retainAll(friendFriends); + // Выполняем запрос и получаем список ID общих друзей + List jointFriendIds = jdbcTemplate.queryForList(sql, Long.class, idUser, idFriend); + // Преобразуем список ID в Set Set result = new HashSet<>(); - for (Long friendId : jointFriends) { + for (Long friendId : jointFriendIds) { result.add(userStorage.findById(friendId)); } + return result; } From e8ca87a67dca5a9ef0a86bb6e027639b9564eb6c Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 22:47:08 +0500 Subject: [PATCH 063/118] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D1=82=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/UserService.java | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 0ac9bd5..9de28d2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -14,7 +14,6 @@ import ru.yandex.practicum.filmorate.storage.user.UserStorage; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; @@ -74,21 +73,17 @@ public Set findJointFriends(Long idUser, Long idFriend) { validateUserExists(idUser); validateUserExists(idFriend); - // SQL-запрос для поиска общих друзей - String sql = "SELECT f1.friend_id " + - "FROM friends f1 " + - "INNER JOIN friends f2 ON f1.friend_id = f2.friend_id " + - "WHERE f1.user_id = ? AND f2.user_id = ?"; + Map> friends = jdbcTemplate.query(SQL_SELECT_FRIENDS, new UserDbStorage.FriendsExtractor()); + Set userFriends = friends.getOrDefault(idUser, new HashSet<>()); + Set friendFriends = friends.getOrDefault(idFriend, new HashSet<>()); - // Выполняем запрос и получаем список ID общих друзей - List jointFriendIds = jdbcTemplate.queryForList(sql, Long.class, idUser, idFriend); + Set jointFriends = new HashSet<>(userFriends); + jointFriends.retainAll(friendFriends); - // Преобразуем список ID в Set Set result = new HashSet<>(); - for (Long friendId : jointFriendIds) { + for (Long friendId : jointFriends) { result.add(userStorage.findById(friendId)); } - return result; } From de3ef4809223103af7d6c39994aec375d718fe34 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 22:50:14 +0500 Subject: [PATCH 064/118] =?UTF-8?q?defaultValue=20=3D=2010=20=D1=82=D0=B0?= =?UTF-8?q?=D0=BA=20=D0=B6=D0=B5=20=D0=BE=D1=81=D1=82=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/controller/FilmController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index d1c0ab6..6f30a45 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -73,7 +73,7 @@ public FilmResponse delLike(@Valid @PathVariable("id") Long id, @PathVariable("u } @GetMapping("/popular") - public LinkedHashSet viewRating(@RequestParam(required = false) Long count) { + public LinkedHashSet viewRating(@RequestParam(defaultValue = "10") Long count) { return filmInterface.viewRating(count); } From 096d0c7e7bc3dbf5840bef5fb443c20c91971470 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 22:56:48 +0500 Subject: [PATCH 065/118] =?UTF-8?q?=D0=BF=D0=BE=D0=BC=D0=B5=D0=BD=D1=8F?= =?UTF-8?q?=D0=BB=D0=B0=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BE=D0=B1=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0?= =?UTF-8?q?=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/service/FilmService.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 9e937c0..3d3a7e1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -40,8 +40,8 @@ public FilmResponse addLike(Long idUser, Long idFilm) { if (userStorage.findById(idUser) != null && filmStorage.findById(idFilm) != null) { Map> likedUsers = jdbcTemplate.query(selectLikedUsersQuery, new FilmDbStorage.LikedUsersExtractor()); if (likedUsers.get(idFilm) != null && likedUsers.get(idFilm).contains(idUser)) { - log.error("Exception", new ConditionsNotMetException(idUser.toString())); - throw new ConditionsNotMetException(idUser.toString()); + log.error("Пользователь с ID {} уже поставил лайк фильму с ID {}", idUser, idFilm); + throw new ConditionsNotMetException("Пользователь с ID " + idUser + " уже поставил лайк фильму с ID " + idFilm); } else { jdbcTemplate.update(insertLikeQuery, idFilm, idUser); } @@ -62,9 +62,11 @@ public FilmResponse delLike(Long idUser, Long idFilm) { if (userStorage.findById(idUser) != null && filmStorage.findById(idFilm) != null) { Map> likedUsers = jdbcTemplate.query(selectLikedUsersQuery, new FilmDbStorage.LikedUsersExtractor()); if (likedUsers.get(idFilm) != null && !likedUsers.get(idFilm).contains(idUser)) { - log.error("Exception", new ConditionsNotMetException(idUser.toString())); - throw new ConditionsNotMetException(idUser.toString()); - } else jdbcTemplate.update(deleteLikeQuery, idFilm, idUser); + log.error("Пользователь с ID {} не ставил лайк фильму с ID {}", idUser, idFilm); + throw new ConditionsNotMetException("Пользователь с ID " + idUser + " не ставил лайк фильму с ID " + idFilm); + } else { + jdbcTemplate.update(deleteLikeQuery, idFilm, idUser); + } } FilmResponse film = filmStorage.findById(idFilm); LinkedHashSet genres = new LinkedHashSet<>(); @@ -81,7 +83,7 @@ public LinkedHashSet viewRating(Long count) { LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); LinkedHashSet films = new LinkedHashSet<>(); if (likedUsers == null) { - log.error("Exception", new NotFoundException("Список фильмов с рейтингом пуст.")); + log.error("Список фильмов с рейтингом пуст."); throw new NotFoundException("Список фильмов с рейтингом пуст."); } else { LinkedHashSet genres = new LinkedHashSet<>(); From c0347393169f6eefab72968f9944ee83368b372c Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 23:00:46 +0500 Subject: [PATCH 066/118] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B0?= =?UTF-8?q?=D1=8E=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=20cou?= =?UTF-8?q?nt=20=D0=B2=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/FilmService.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 3d3a7e1..d098e58 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -80,9 +80,15 @@ public FilmResponse delLike(Long idUser, Long idFilm) { public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); - LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); + + if (count == null || count <= 0) { + count = 10L; + } + + LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor(), count); + LinkedHashSet films = new LinkedHashSet<>(); - if (likedUsers == null) { + if (likedUsers == null || likedUsers.isEmpty()) { log.error("Список фильмов с рейтингом пуст."); throw new NotFoundException("Список фильмов с рейтингом пуст."); } else { @@ -93,7 +99,16 @@ public LinkedHashSet viewRating(Long count) { for (Long g : filmGenre.get(filmStorage.findById(l).getId())) genres.add(g); } - films.add(FilmResponse.of(filmStorage.findById(l).getId(), filmStorage.findById(l).getName(), filmStorage.findById(l).getDescription(), filmStorage.findById(l).getReleaseDate(), filmStorage.findById(l).getDuration(), new HashSet<>(), filmStorage.findById(l).getMpa(), genres)); + films.add(FilmResponse.of( + filmStorage.findById(l).getId(), + filmStorage.findById(l).getName(), + filmStorage.findById(l).getDescription(), + filmStorage.findById(l).getReleaseDate(), + filmStorage.findById(l).getDuration(), + new HashSet<>(), + filmStorage.findById(l).getMpa(), + genres + )); } } return films; From cd8b0d75b60076f7adf68654305069b935a2da9f Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 23:12:34 +0500 Subject: [PATCH 067/118] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D1=82=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/FilmService.java | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index d098e58..3d3a7e1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -80,15 +80,9 @@ public FilmResponse delLike(Long idUser, Long idFilm) { public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); - - if (count == null || count <= 0) { - count = 10L; - } - - LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor(), count); - + LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); LinkedHashSet films = new LinkedHashSet<>(); - if (likedUsers == null || likedUsers.isEmpty()) { + if (likedUsers == null) { log.error("Список фильмов с рейтингом пуст."); throw new NotFoundException("Список фильмов с рейтингом пуст."); } else { @@ -99,16 +93,7 @@ public LinkedHashSet viewRating(Long count) { for (Long g : filmGenre.get(filmStorage.findById(l).getId())) genres.add(g); } - films.add(FilmResponse.of( - filmStorage.findById(l).getId(), - filmStorage.findById(l).getName(), - filmStorage.findById(l).getDescription(), - filmStorage.findById(l).getReleaseDate(), - filmStorage.findById(l).getDuration(), - new HashSet<>(), - filmStorage.findById(l).getMpa(), - genres - )); + films.add(FilmResponse.of(filmStorage.findById(l).getId(), filmStorage.findById(l).getName(), filmStorage.findById(l).getDescription(), filmStorage.findById(l).getReleaseDate(), filmStorage.findById(l).getDuration(), new HashSet<>(), filmStorage.findById(l).getMpa(), genres)); } } return films; From 1f37ed4c014c7ec01efbce427dbf2cce799bbeb1 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 23:16:26 +0500 Subject: [PATCH 068/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D1=8E=D1=8E=20=D0=B0=D0=BD=D0=BD=D0=BE?= =?UTF-8?q?=D1=82=D0=B0=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/film/FilmDbStorage.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 6fd0689..27a07bb 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -25,8 +25,6 @@ @Repository @RequiredArgsConstructor @Slf4j(topic = "TRACE") -@ConfigurationPropertiesScan -@Component @Qualifier("FilmDbStorage") public class FilmDbStorage implements FilmStorage { From 6a6b99aacbf6d306813f50f2b198bc015ad2bdc7 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 23:18:04 +0500 Subject: [PATCH 069/118] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/film/FilmDbStorage.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 27a07bb..71e3c6e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -4,12 +4,10 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; -import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; From 2ce3532b0f73de4eaaa89a996f0d1bad961b8a41 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 23:26:27 +0500 Subject: [PATCH 070/118] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BB=D0=B0=20=D0=B7=D0=B0=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=81=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/user/UserDbStorage.java | 62 +++++++++---------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 59fc5e8..863ff13 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -26,22 +26,28 @@ @Repository @RequiredArgsConstructor @Slf4j(topic = "TRACE") -@ConfigurationPropertiesScan -@Component @Qualifier("UserDbStorage") public class UserDbStorage implements UserStorage { private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private final JdbcTemplate jdbcTemplate; - private final String sqlQuery1 = "select id, name, email, login, birthday from users"; - private final String sqlQuery2 = "select userId, friendId from friends"; - private final String sqlQuery3 = "select id, name, email, login, birthday from users where id = ?"; - private final String sqlQuery4 = "select email from users"; - private final String sqlQuery5 = "update users set " + "name = ?, email = ?, login = ?, birthday = ? " + "where id = ?"; + private final String SELECT_ALL_USERS = "SELECT id, name, email, login, birthday FROM users"; + private final String SELECT_ALL_FRIENDSHIPS = "SELECT userId, friendId FROM friends"; + private final String SELECT_USER_BY_ID = "SELECT id, name, email, login, birthday FROM users WHERE id = ?"; + private final String SELECT_ALL_EMAILS = "SELECT email FROM users"; + private final String UPDATE_USER = "UPDATE users SET name = ?, email = ?, login = ?, birthday = ? WHERE id = ?"; private User mapRowToUser(ResultSet resultSet, int rowNum) throws SQLException { - return User.builder().id(resultSet.getLong("id")).name(resultSet.getString("name")).email(resultSet.getString("email")).login(resultSet.getString("login")).birthday(resultSet.getDate("birthday").toLocalDate()).friends(new HashSet<>()).friendRequests(new HashSet<>()).build(); + return User.builder() + .id(resultSet.getLong("id")) + .name(resultSet.getString("name")) + .email(resultSet.getString("email")) + .login(resultSet.getString("login")) + .birthday(resultSet.getDate("birthday").toLocalDate()) + .friends(new HashSet<>()) + .friendRequests(new HashSet<>()) + .build(); } public static class FriendsExtractor implements ResultSetExtractor>> { @@ -70,29 +76,29 @@ public Set extractData(ResultSet rs) throws SQLException { } } + @Override public Collection findAll() { log.info("Обработка Get-запроса..."); - Collection users = jdbcTemplate.query(sqlQuery1, this::mapRowToUser); - Map> friends = jdbcTemplate.query(sqlQuery2, new FriendsExtractor()); + Collection users = jdbcTemplate.query(SELECT_ALL_USERS, this::mapRowToUser); + Map> friends = jdbcTemplate.query(SELECT_ALL_FRIENDSHIPS, new FriendsExtractor()); for (User user : users) { user.setFriends(friends.get(user.getId())); } return users; } + @Override public User findById(Long id) { log.info("Обработка Get-запроса..."); - if (id != 0 && !id.equals(null)) { + if (id != 0 && id != null) { try { - jdbcTemplate.queryForObject(sqlQuery3, this::mapRowToUser, id); + jdbcTemplate.queryForObject(SELECT_USER_BY_ID, this::mapRowToUser, id); } catch (DataAccessException e) { - if (e != null) { - log.error("Exception", new NotFoundException("Пользователь с данным идентификатором отсутствует в базе")); - throw new NotFoundException("Пользователь с данным идентификатором отсутствует в базе"); - } + log.error("Exception", new NotFoundException("Пользователь с данным идентификатором отсутствует в базе")); + throw new NotFoundException("Пользователь с данным идентификатором отсутствует в базе"); } - User user = jdbcTemplate.queryForObject(sqlQuery3, this::mapRowToUser, id); - Map> friends = jdbcTemplate.query(sqlQuery2, new FriendsExtractor()); + User user = jdbcTemplate.queryForObject(SELECT_USER_BY_ID, this::mapRowToUser, id); + Map> friends = jdbcTemplate.query(SELECT_ALL_FRIENDSHIPS, new FriendsExtractor()); user.setFriends(friends.get(id)); return user; } else { @@ -105,28 +111,24 @@ public Collection getFriends(Long id) { return List.of(); } + @Override public User create(@Valid User user) { log.info("Обработка Create-запроса..."); - // Проверка на дубликат email duplicateCheck(user); - // Проверка email if (user.getEmail() == null || user.getEmail().isBlank() || !user.getEmail().contains("@")) { throw new ValidationException("Электронная почта не может быть пустой и должна содержать символ @"); } - // Проверка логина if (user.getLogin() == null || user.getLogin().isBlank() || user.getLogin().contains(" ")) { throw new ValidationException("Логин не может быть пустым и содержать пробелы"); } - // Проверка имени if (user.getName() == null || user.getName().isBlank()) { user.setName(user.getLogin()); } - // Проверка даты рождения if (user.getBirthday() == null) { throw new ValidationException("Дата рождения не может быть нулевой"); } @@ -134,7 +136,6 @@ public User create(@Valid User user) { throw new ValidationException("Дата рождения не может быть в будущем"); } - // Создание пользователя SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate) .withTableName("users") .usingGeneratedKeyColumns("id"); @@ -145,48 +146,42 @@ public User create(@Valid User user) { } private void duplicateCheck(User user) { - Set emails = jdbcTemplate.query(sqlQuery4, new EmailExtractor()); + Set emails = jdbcTemplate.query(SELECT_ALL_EMAILS, new EmailExtractor()); if (emails.contains(user.getEmail())) { log.error("Exception", new DuplicatedDataException("Этот имейл уже используется")); throw new DuplicatedDataException("Этот имейл уже используется"); } } + @Override public User update(@Valid User newUser) { log.info("Обработка Update-запроса..."); - // Проверка на наличие ID if (newUser.getId() == null) { throw new ValidationException("Id должен быть указан"); } - // Поиск существующего пользователя User oldUser = findById(newUser.getId()); if (oldUser == null) { throw new NotFoundException("Пользователь с указанным id не найден"); } - // Проверка email if (newUser.getEmail() == null || newUser.getEmail().isBlank() || !newUser.getEmail().contains("@")) { throw new ValidationException("Электронная почта не может быть пустой и должна содержать символ @"); } - // Проверка на дубликат email if (!newUser.getEmail().equals(oldUser.getEmail())) { duplicateCheck(newUser); } - // Проверка логина if (newUser.getLogin() == null || newUser.getLogin().isBlank() || newUser.getLogin().contains(" ")) { throw new ValidationException("Логин не может быть пустым и содержать пробелы"); } - // Проверка имени if (newUser.getName() == null || newUser.getName().isBlank()) { newUser.setName(newUser.getLogin()); } - // Проверка даты рождения if (newUser.getBirthday() == null) { throw new ValidationException("Дата рождения не может быть нулевой"); } @@ -194,8 +189,7 @@ public User update(@Valid User newUser) { throw new ValidationException("Дата рождения не может быть в будущем"); } - // Обновление пользователя - jdbcTemplate.update(sqlQuery5, + jdbcTemplate.update(UPDATE_USER, newUser.getName(), newUser.getEmail(), newUser.getLogin(), From 6ac56150e894fdf4bf3f1346e1abd53f223183eb Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 23:28:45 +0500 Subject: [PATCH 071/118] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/user/UserDbStorage.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 863ff13..0137f29 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -4,12 +4,10 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; -import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; From 4d7f8bd538ef7c5a9dd520ed766f3aaa836360e7 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 23:34:08 +0500 Subject: [PATCH 072/118] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=B8=D0=B8=D0=BB?= =?UTF-8?q?=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/user/UserDbStorage.java | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 0137f29..d68c3c4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -30,11 +30,12 @@ public class UserDbStorage implements UserStorage { private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private final JdbcTemplate jdbcTemplate; - private final String SELECT_ALL_USERS = "SELECT id, name, email, login, birthday FROM users"; - private final String SELECT_ALL_FRIENDSHIPS = "SELECT userId, friendId FROM friends"; - private final String SELECT_USER_BY_ID = "SELECT id, name, email, login, birthday FROM users WHERE id = ?"; - private final String SELECT_ALL_EMAILS = "SELECT email FROM users"; - private final String UPDATE_USER = "UPDATE users SET name = ?, email = ?, login = ?, birthday = ? WHERE id = ?"; + // Переименованные запросы в camelCase + private final String selectAllUsers = "SELECT id, name, email, login, birthday FROM users"; + private final String selectAllFriendships = "SELECT userId, friendId FROM friends"; + private final String selectUserById = "SELECT id, name, email, login, birthday FROM users WHERE id = ?"; + private final String selectAllEmails = "SELECT email FROM users"; + private final String updateUser = "UPDATE users SET name = ?, email = ?, login = ?, birthday = ? WHERE id = ?"; private User mapRowToUser(ResultSet resultSet, int rowNum) throws SQLException { return User.builder() @@ -77,8 +78,8 @@ public Set extractData(ResultSet rs) throws SQLException { @Override public Collection findAll() { log.info("Обработка Get-запроса..."); - Collection users = jdbcTemplate.query(SELECT_ALL_USERS, this::mapRowToUser); - Map> friends = jdbcTemplate.query(SELECT_ALL_FRIENDSHIPS, new FriendsExtractor()); + Collection users = jdbcTemplate.query(selectAllUsers, this::mapRowToUser); + Map> friends = jdbcTemplate.query(selectAllFriendships, new FriendsExtractor()); for (User user : users) { user.setFriends(friends.get(user.getId())); } @@ -90,13 +91,13 @@ public User findById(Long id) { log.info("Обработка Get-запроса..."); if (id != 0 && id != null) { try { - jdbcTemplate.queryForObject(SELECT_USER_BY_ID, this::mapRowToUser, id); + jdbcTemplate.queryForObject(selectUserById, this::mapRowToUser, id); } catch (DataAccessException e) { log.error("Exception", new NotFoundException("Пользователь с данным идентификатором отсутствует в базе")); throw new NotFoundException("Пользователь с данным идентификатором отсутствует в базе"); } - User user = jdbcTemplate.queryForObject(SELECT_USER_BY_ID, this::mapRowToUser, id); - Map> friends = jdbcTemplate.query(SELECT_ALL_FRIENDSHIPS, new FriendsExtractor()); + User user = jdbcTemplate.queryForObject(selectUserById, this::mapRowToUser, id); + Map> friends = jdbcTemplate.query(selectAllFriendships, new FriendsExtractor()); user.setFriends(friends.get(id)); return user; } else { @@ -144,7 +145,7 @@ public User create(@Valid User user) { } private void duplicateCheck(User user) { - Set emails = jdbcTemplate.query(SELECT_ALL_EMAILS, new EmailExtractor()); + Set emails = jdbcTemplate.query(selectAllEmails, new EmailExtractor()); if (emails.contains(user.getEmail())) { log.error("Exception", new DuplicatedDataException("Этот имейл уже используется")); throw new DuplicatedDataException("Этот имейл уже используется"); @@ -155,31 +156,38 @@ private void duplicateCheck(User user) { public User update(@Valid User newUser) { log.info("Обработка Update-запроса..."); + // Проверка на наличие ID if (newUser.getId() == null) { throw new ValidationException("Id должен быть указан"); } + // Поиск существующего пользователя User oldUser = findById(newUser.getId()); if (oldUser == null) { throw new NotFoundException("Пользователь с указанным id не найден"); } + // Проверка email if (newUser.getEmail() == null || newUser.getEmail().isBlank() || !newUser.getEmail().contains("@")) { throw new ValidationException("Электронная почта не может быть пустой и должна содержать символ @"); } + // Проверка на дубликат email if (!newUser.getEmail().equals(oldUser.getEmail())) { duplicateCheck(newUser); } + // Проверка логина if (newUser.getLogin() == null || newUser.getLogin().isBlank() || newUser.getLogin().contains(" ")) { throw new ValidationException("Логин не может быть пустым и содержать пробелы"); } + // Проверка имени if (newUser.getName() == null || newUser.getName().isBlank()) { newUser.setName(newUser.getLogin()); } + // Проверка даты рождения if (newUser.getBirthday() == null) { throw new ValidationException("Дата рождения не может быть нулевой"); } @@ -187,7 +195,8 @@ public User update(@Valid User newUser) { throw new ValidationException("Дата рождения не может быть в будущем"); } - jdbcTemplate.update(UPDATE_USER, + // Обновление пользователя + jdbcTemplate.update(updateUser, newUser.getName(), newUser.getEmail(), newUser.getLogin(), From 8efda5079ce40a1e30706b1212e360e6123cada3 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 23:42:00 +0500 Subject: [PATCH 073/118] =?UTF-8?q?=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=D0=BB?= =?UTF-8?q?=D0=B0=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/UserService.java | 7 ++-- .../storage/user/EmailExtractor.java | 19 +++++++++++ .../storage/user/FriendsExtractor.java | 21 ++++++++++++ .../filmorate/storage/user/UserDbStorage.java | 34 ------------------- 4 files changed, 44 insertions(+), 37 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/user/EmailExtractor.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/user/FriendsExtractor.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 9de28d2..25455f6 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -10,6 +10,7 @@ import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.storage.user.FriendsExtractor; import ru.yandex.practicum.filmorate.storage.user.UserDbStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; @@ -73,7 +74,7 @@ public Set findJointFriends(Long idUser, Long idFriend) { validateUserExists(idUser); validateUserExists(idFriend); - Map> friends = jdbcTemplate.query(SQL_SELECT_FRIENDS, new UserDbStorage.FriendsExtractor()); + Map> friends = jdbcTemplate.query(SQL_SELECT_FRIENDS, new FriendsExtractor()); Set userFriends = friends.getOrDefault(idUser, new HashSet<>()); Set friendFriends = friends.getOrDefault(idFriend, new HashSet<>()); @@ -93,7 +94,7 @@ public Set findAllFriends(Long idUser) { validateUserExists(idUser); - Map> friends = jdbcTemplate.query(SQL_SELECT_FRIENDS, new UserDbStorage.FriendsExtractor()); + Map> friends = jdbcTemplate.query(SQL_SELECT_FRIENDS, new FriendsExtractor()); assert friends != null; Set userFriends = friends.getOrDefault(idUser, new HashSet<>()); @@ -111,7 +112,7 @@ private void validateUserExists(Long userId) { } private boolean isFriend(Long idUser, Long idFriend) { - Map> friends = jdbcTemplate.query(SQL_SELECT_FRIENDS, new UserDbStorage.FriendsExtractor()); + Map> friends = jdbcTemplate.query(SQL_SELECT_FRIENDS, new FriendsExtractor()); assert friends != null; return friends.getOrDefault(idUser, new HashSet<>()).contains(idFriend); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/EmailExtractor.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/EmailExtractor.java new file mode 100644 index 0000000..3587d50 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/EmailExtractor.java @@ -0,0 +1,19 @@ +package ru.yandex.practicum.filmorate.storage.user; + +import org.springframework.jdbc.core.ResultSetExtractor; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + +public class EmailExtractor implements ResultSetExtractor> { + + @Override + public Set extractData(ResultSet rs) throws SQLException { + Set data = new HashSet<>(); + while (rs.next()) { + String email = rs.getString("email"); + data.add(email); + } + return data; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/FriendsExtractor.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/FriendsExtractor.java new file mode 100644 index 0000000..fb5b074 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/FriendsExtractor.java @@ -0,0 +1,21 @@ +package ru.yandex.practicum.filmorate.storage.user; + +import org.springframework.jdbc.core.ResultSetExtractor; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + +public class FriendsExtractor implements ResultSetExtractor>> { + + @Override + public Map> extractData(ResultSet rs) throws SQLException { + Map> data = new LinkedHashMap<>(); + while (rs.next()) { + Long userId = rs.getLong("userId"); + data.putIfAbsent(userId, new HashSet<>()); + Long friendId = rs.getLong("friendId"); + data.get(userId).add(friendId); + } + return data; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index d68c3c4..59d3f1f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -49,32 +49,6 @@ private User mapRowToUser(ResultSet resultSet, int rowNum) throws SQLException { .build(); } - public static class FriendsExtractor implements ResultSetExtractor>> { - @Override - public Map> extractData(ResultSet rs) throws SQLException { - Map> data = new LinkedHashMap<>(); - while (rs.next()) { - Long userId = rs.getLong("userId"); - data.putIfAbsent(userId, new HashSet<>()); - Long friendId = rs.getLong("friendId"); - data.get(userId).add(friendId); - } - return data; - } - } - - public static class EmailExtractor implements ResultSetExtractor> { - @Override - public Set extractData(ResultSet rs) throws SQLException { - Set data = new HashSet<>(); - while (rs.next()) { - String email = rs.getString("email"); - data.add(email); - } - return data; - } - } - @Override public Collection findAll() { log.info("Обработка Get-запроса..."); @@ -156,38 +130,31 @@ private void duplicateCheck(User user) { public User update(@Valid User newUser) { log.info("Обработка Update-запроса..."); - // Проверка на наличие ID if (newUser.getId() == null) { throw new ValidationException("Id должен быть указан"); } - // Поиск существующего пользователя User oldUser = findById(newUser.getId()); if (oldUser == null) { throw new NotFoundException("Пользователь с указанным id не найден"); } - // Проверка email if (newUser.getEmail() == null || newUser.getEmail().isBlank() || !newUser.getEmail().contains("@")) { throw new ValidationException("Электронная почта не может быть пустой и должна содержать символ @"); } - // Проверка на дубликат email if (!newUser.getEmail().equals(oldUser.getEmail())) { duplicateCheck(newUser); } - // Проверка логина if (newUser.getLogin() == null || newUser.getLogin().isBlank() || newUser.getLogin().contains(" ")) { throw new ValidationException("Логин не может быть пустым и содержать пробелы"); } - // Проверка имени if (newUser.getName() == null || newUser.getName().isBlank()) { newUser.setName(newUser.getLogin()); } - // Проверка даты рождения if (newUser.getBirthday() == null) { throw new ValidationException("Дата рождения не может быть нулевой"); } @@ -195,7 +162,6 @@ public User update(@Valid User newUser) { throw new ValidationException("Дата рождения не может быть в будущем"); } - // Обновление пользователя jdbcTemplate.update(updateUser, newUser.getName(), newUser.getEmail(), From c450028026eb5bc9b26f4be989eec21f8cb0d7f9 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 23:44:17 +0500 Subject: [PATCH 074/118] =?UTF-8?q?=D1=81=D0=BF=D0=B0=D1=81=D0=B8=D1=82?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ru/yandex/practicum/filmorate/service/UserService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 25455f6..8806ede 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -11,7 +11,6 @@ import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.storage.user.FriendsExtractor; -import ru.yandex.practicum.filmorate.storage.user.UserDbStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; import java.util.HashSet; From 2936d2fd5e1158c7646209953626b68421f6f67f Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 23:46:07 +0500 Subject: [PATCH 075/118] =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=83=D0=B6=D0=BD?= =?UTF-8?q?=D1=8B=D0=B5=20=D0=B8=D0=BC=D0=BF=D0=BE=D1=80=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/user/UserDbStorage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 59d3f1f..4814241 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -6,7 +6,6 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; From acbdf270a38dac9a4013fa3abcfa6d07f286a610 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Sun, 2 Mar 2025 23:48:58 +0500 Subject: [PATCH 076/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=BD=D0=B5=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=8B=D0=B9=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/storage/user/UserDbStorage.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 4814241..671c5b4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -79,10 +79,6 @@ public User findById(Long id) { } } - public Collection getFriends(Long id) { - return List.of(); - } - @Override public User create(@Valid User user) { log.info("Обработка Create-запроса..."); From 07f40cdf92c892bfdb43d029d1715500ed8d0a25 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 00:02:28 +0500 Subject: [PATCH 077/118] =?UTF-8?q?=D0=BF=D0=BE=D0=BC=D0=B5=D0=BD=D1=8F?= =?UTF-8?q?=D0=BB=D0=B0=20=D0=B0=D0=BD=D0=BD=D0=BE=D1=82=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/film/FilmDbStorage.java | 3 ++- .../yandex/practicum/filmorate/storage/user/UserDbStorage.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 71e3c6e..674f23a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -8,6 +8,7 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; @@ -23,7 +24,7 @@ @Repository @RequiredArgsConstructor @Slf4j(topic = "TRACE") -@Qualifier("FilmDbStorage") +@Component public class FilmDbStorage implements FilmStorage { //SQL-запросы diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 671c5b4..13dc59c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -7,6 +7,7 @@ import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; @@ -23,7 +24,7 @@ @Repository @RequiredArgsConstructor @Slf4j(topic = "TRACE") -@Qualifier("UserDbStorage") +@Component public class UserDbStorage implements UserStorage { private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); From a61057c8733b951d950cb99b4c3c5e77f5125c9b Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 00:05:03 +0500 Subject: [PATCH 078/118] =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=83=D0=B6=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20import?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/film/FilmDbStorage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 674f23a..5f13a5b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -3,7 +3,6 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; From dd74d6f2e3a982e5c05af9cb38d6a582f44aff64 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 00:07:20 +0500 Subject: [PATCH 079/118] =?UTF-8?q?=D0=BF=D0=BE=D1=80=D0=B0=20=D0=B1=D1=8B?= =?UTF-8?q?=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B8=D1=82=D1=8C=20?= =?UTF-8?q?=D0=B8=D0=B4=D0=B5=D1=8E=20=D0=BD=D0=B0=20=D1=83=D0=B4=D0=B0?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B5=D0=BD=D1=83=D0=B6?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D0=B8=D0=BC=D0=BF=D0=BE=D1=80=D1=82=D0=BE?= =?UTF-8?q?=D0=B2,=20=D0=B4=D0=B0=3F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/user/UserDbStorage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 13dc59c..723fd1f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -3,7 +3,6 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; From d37c60937e1ed3a29abff30cb385f246547bfe7f Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 00:11:39 +0500 Subject: [PATCH 080/118] =?UTF-8?q?=D0=B1=D0=B5=D0=B7=20=D0=B0=D0=BD=D0=BD?= =?UTF-8?q?=D0=BE=D1=82=D0=B0=D1=86=D0=B8=D0=B9=20=D0=B2=D0=BE=D0=BE=D0=B1?= =?UTF-8?q?=D1=89=D0=B5=20=D0=B2=D1=81=D0=B5=20=D0=BF=D0=B0=D0=B4=D0=B0?= =?UTF-8?q?=D0=B5=D1=82,=20=D0=B2=D0=B5=D1=80=D0=BD=D1=83=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=80=D0=B0=D1=82=D0=BD=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/storage/film/FilmDbStorage.java | 4 ++-- .../practicum/filmorate/storage/user/UserDbStorage.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 5f13a5b..71e3c6e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -3,11 +3,11 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; -import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; @@ -23,7 +23,7 @@ @Repository @RequiredArgsConstructor @Slf4j(topic = "TRACE") -@Component +@Qualifier("FilmDbStorage") public class FilmDbStorage implements FilmStorage { //SQL-запросы diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 723fd1f..671c5b4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -3,10 +3,10 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; -import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.DuplicatedDataException; @@ -23,7 +23,7 @@ @Repository @RequiredArgsConstructor @Slf4j(topic = "TRACE") -@Component +@Qualifier("UserDbStorage") public class UserDbStorage implements UserStorage { private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); From c7d8b6bf41d067f96f179fabd2415b16263429e5 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 00:31:34 +0500 Subject: [PATCH 081/118] =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B4=D1=80=D1=83=D0=B7=D0=B5=D0=B9=20?= =?UTF-8?q?=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20=D0=BE=D0=B4=D0=B8=D0=BD=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/service/UserService.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 8806ede..3cef25d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -73,15 +73,16 @@ public Set findJointFriends(Long idUser, Long idFriend) { validateUserExists(idUser); validateUserExists(idFriend); - Map> friends = jdbcTemplate.query(SQL_SELECT_FRIENDS, new FriendsExtractor()); - Set userFriends = friends.getOrDefault(idUser, new HashSet<>()); - Set friendFriends = friends.getOrDefault(idFriend, new HashSet<>()); + String SQL_SELECT_JOINT_FRIENDS = "SELECT f1.friendId AS jointFriendId " + + "FROM friends f1 " + + "JOIN friends f2 ON f1.friendId = f2.friendId " + + "WHERE f1.userId = ? AND f2.userId = ?"; - Set jointFriends = new HashSet<>(userFriends); - jointFriends.retainAll(friendFriends); + Set jointFriendIds = new HashSet<>(jdbcTemplate.queryForList( + SQL_SELECT_JOINT_FRIENDS, Long.class, idUser, idFriend)); Set result = new HashSet<>(); - for (Long friendId : jointFriends) { + for (Long friendId : jointFriendIds) { result.add(userStorage.findById(friendId)); } return result; From 051172f5be621b2fc7f8a415019295558af4cf67 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 00:35:08 +0500 Subject: [PATCH 082/118] =?UTF-8?q?=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD?= =?UTF-8?q?=D0=BE=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/service/UserService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 3cef25d..9a39c5a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -73,13 +73,13 @@ public Set findJointFriends(Long idUser, Long idFriend) { validateUserExists(idUser); validateUserExists(idFriend); - String SQL_SELECT_JOINT_FRIENDS = "SELECT f1.friendId AS jointFriendId " + + String sqlSelectJointFriends = "SELECT f1.friendId AS jointFriendId " + "FROM friends f1 " + "JOIN friends f2 ON f1.friendId = f2.friendId " + "WHERE f1.userId = ? AND f2.userId = ?"; Set jointFriendIds = new HashSet<>(jdbcTemplate.queryForList( - SQL_SELECT_JOINT_FRIENDS, Long.class, idUser, idFriend)); + sqlSelectJointFriends, Long.class, idUser, idFriend)); Set result = new HashSet<>(); for (Long friendId : jointFriendIds) { From 30950165c64f7ced0dbf343ecaafd14cfbf406a6 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 00:59:22 +0500 Subject: [PATCH 083/118] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B1=D1=83=D0=B5?= =?UTF-8?q?=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 50 ++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 71e3c6e..fd21e7d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -19,6 +19,7 @@ import java.sql.SQLException; import java.time.LocalDate; import java.util.*; +import java.util.stream.Collectors; @Repository @RequiredArgsConstructor @@ -103,22 +104,45 @@ public Map extractData(ResultSet rs) throws SQLException { @Override public List findAll() { log.info(LOG_GET_REQUEST); - String sqlQuery1 = "select id, name, description, releaseDate, duration from film"; - List films = jdbcTemplate.query(sqlQuery1, this::mapRowToFilm); - String sqlQuery2 = "select filmId, userId from likedUsers"; - Map> likedUsers = jdbcTemplate.query(sqlQuery2, new LikedUsersExtractor()); - String sqlQuery3 = "select filmId, genreId from filmGenre"; - Map> filmGenre = jdbcTemplate.query(sqlQuery3, new FilmGenreExtractor()); - String sqlQuery4 = "select id, ratingId from film"; - Map filmRating = jdbcTemplate.query(sqlQuery4, new FilmRatingExtractor()); - for (Film film : films) { - film.setLikedUsers(likedUsers.get(film.getId())); - film.setGenres(filmGenre.get(film.getId())); - film.setMpa(filmRating.get(film.getId())); - } + String sqlQuery = """ + SELECT f.id, f.name, f.description, f.releaseDate, f.duration, + GROUP_CONCAT(DISTINCT fg.genreId) AS genreIds, + GROUP_CONCAT(DISTINCT lu.userId) AS likedUserIds, + f.ratingId + FROM film f + LEFT JOIN filmGenre fg ON f.id = fg.filmId + LEFT JOIN likedUsers lu ON f.id = lu.filmId + GROUP BY f.id + """; + + List films = jdbcTemplate.query(sqlQuery, (rs, rowNum) -> { + Film film = mapRowToFilm(rs, rowNum); + + String genreIds = rs.getString("genreIds"); + if (genreIds != null) { + LinkedHashSet genres = Arrays.stream(genreIds.split(",")) + .map(Long::parseLong) + .collect(Collectors.toCollection(LinkedHashSet::new)); + film.setGenres(genres); + } + + String likedUserIds = rs.getString("likedUserIds"); + if (likedUserIds != null) { + Set likedUsers = Arrays.stream(likedUserIds.split(",")) + .map(Long::parseLong) + .collect(Collectors.toSet()); + film.setLikedUsers(likedUsers); + } + + film.setMpa(rs.getLong("ratingId")); + + return film; + }); + return films; } + @Override public FilmResponse findById(Long id) { log.info(LOG_GET_REQUEST); From 1b2cbfa260440d35dcf1c9156606b5754adf01ae Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 01:04:51 +0500 Subject: [PATCH 084/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index fd21e7d..ce0f4e4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -253,21 +253,34 @@ private void validateBuffer(Buffer buffer) { private LinkedHashSet processGenres(List genres, Long filmId, Map genreMap) { LinkedHashSet result = new LinkedHashSet<>(); + + // Если список жанров пуст или содержит "нет жанра", возвращаем пустой результат if (genres == null || genres.equals(List.of("нет жанра"))) { return result; } - for (String genreIdStr : genres) { - Long genreId = Long.parseLong(genreIdStr); - if (!(genreId > 0 && genreId < 7)) { - logAndThrowNotFoundException(genreId.toString(), ERROR_INVALID_GENRE); + for (String genreName : genres) { + // Проверяем наличие жанра в базе данных по имени + Long genreId = jdbcTemplate.queryForObject( + "SELECT id FROM genres WHERE name = ?", + Long.class, + genreName + ); + + if (genreId == null) { + logAndThrowNotFoundException(genreName, ERROR_INVALID_GENRE); } + + // Вставляем жанр в связь фильм-жанр jdbcTemplate.update(SQL_INSERT_FILM_GENRE, filmId, genreId); + + // Добавляем жанр в результат result.add(Genre.of(genreId, genreMap.get(genreId))); } return result; } + private void updateFilmRating(Long mpaId, Long filmId) { jdbcTemplate.update(SQL_UPDATE_FILM_RATING, mpaId, filmId); } From efa09abe183a7d29c4f6fa6eb7679383ec46e7b0 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 01:08:53 +0500 Subject: [PATCH 085/118] =?UTF-8?q?=D0=B2=D0=BE=D0=B7=D0=B2=D1=80=D0=B0?= =?UTF-8?q?=D1=82=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 40 +++++++------------ 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index ce0f4e4..ff7e82b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -105,15 +105,15 @@ public Map extractData(ResultSet rs) throws SQLException { public List findAll() { log.info(LOG_GET_REQUEST); String sqlQuery = """ - SELECT f.id, f.name, f.description, f.releaseDate, f.duration, - GROUP_CONCAT(DISTINCT fg.genreId) AS genreIds, - GROUP_CONCAT(DISTINCT lu.userId) AS likedUserIds, - f.ratingId - FROM film f - LEFT JOIN filmGenre fg ON f.id = fg.filmId - LEFT JOIN likedUsers lu ON f.id = lu.filmId - GROUP BY f.id - """; + SELECT f.id, f.name, f.description, f.releaseDate, f.duration, + GROUP_CONCAT(DISTINCT fg.genreId) AS genreIds, + GROUP_CONCAT(DISTINCT lu.userId) AS likedUserIds, + f.ratingId + FROM film f + LEFT JOIN filmGenre fg ON f.id = fg.filmId + LEFT JOIN likedUsers lu ON f.id = lu.filmId + GROUP BY f.id + """; List films = jdbcTemplate.query(sqlQuery, (rs, rowNum) -> { Film film = mapRowToFilm(rs, rowNum); @@ -143,6 +143,7 @@ public List findAll() { } + @Override public FilmResponse findById(Long id) { log.info(LOG_GET_REQUEST); @@ -253,34 +254,21 @@ private void validateBuffer(Buffer buffer) { private LinkedHashSet processGenres(List genres, Long filmId, Map genreMap) { LinkedHashSet result = new LinkedHashSet<>(); - - // Если список жанров пуст или содержит "нет жанра", возвращаем пустой результат if (genres == null || genres.equals(List.of("нет жанра"))) { return result; } - for (String genreName : genres) { - // Проверяем наличие жанра в базе данных по имени - Long genreId = jdbcTemplate.queryForObject( - "SELECT id FROM genres WHERE name = ?", - Long.class, - genreName - ); - - if (genreId == null) { - logAndThrowNotFoundException(genreName, ERROR_INVALID_GENRE); + for (String genreIdStr : genres) { + Long genreId = Long.parseLong(genreIdStr); + if (!(genreId > 0 && genreId < 7)) { + logAndThrowNotFoundException(genreId.toString(), ERROR_INVALID_GENRE); } - - // Вставляем жанр в связь фильм-жанр jdbcTemplate.update(SQL_INSERT_FILM_GENRE, filmId, genreId); - - // Добавляем жанр в результат result.add(Genre.of(genreId, genreMap.get(genreId))); } return result; } - private void updateFilmRating(Long mpaId, Long filmId) { jdbcTemplate.update(SQL_UPDATE_FILM_RATING, mpaId, filmId); } From a2f9c7b6edcc88f030a8c5072ac42420a0b6bca9 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 01:29:00 +0500 Subject: [PATCH 086/118] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B1=D1=83=D0=B5?= =?UTF-8?q?=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 110 ++++++++++-------- 1 file changed, 61 insertions(+), 49 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index ff7e82b..f72b7d0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -7,7 +7,6 @@ import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; -import org.springframework.jdbc.core.simple.SimpleJdbcInsert; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; @@ -105,15 +104,15 @@ public Map extractData(ResultSet rs) throws SQLException { public List findAll() { log.info(LOG_GET_REQUEST); String sqlQuery = """ - SELECT f.id, f.name, f.description, f.releaseDate, f.duration, - GROUP_CONCAT(DISTINCT fg.genreId) AS genreIds, - GROUP_CONCAT(DISTINCT lu.userId) AS likedUserIds, - f.ratingId - FROM film f - LEFT JOIN filmGenre fg ON f.id = fg.filmId - LEFT JOIN likedUsers lu ON f.id = lu.filmId - GROUP BY f.id - """; + SELECT f.id, f.name, f.description, f.releaseDate, f.duration, + GROUP_CONCAT(DISTINCT fg.genreId) AS genreIds, + GROUP_CONCAT(DISTINCT lu.userId) AS likedUserIds, + f.ratingId + FROM film f + LEFT JOIN filmGenre fg ON f.id = fg.filmId + LEFT JOIN likedUsers lu ON f.id = lu.filmId + GROUP BY f.id + """; List films = jdbcTemplate.query(sqlQuery, (rs, rowNum) -> { Film film = mapRowToFilm(rs, rowNum); @@ -143,7 +142,6 @@ public List findAll() { } - @Override public FilmResponse findById(Long id) { log.info(LOG_GET_REQUEST); @@ -151,55 +149,69 @@ public FilmResponse findById(Long id) { logAndThrowConditionsNotMetException(ERROR_NULL_ID); } - String sqlQuery5 = "select id, name, description, releaseDate, duration from film where id = ?"; + String sqlQuery = """ + SELECT f.id, f.name, f.description, f.releaseDate, f.duration, + GROUP_CONCAT(DISTINCT g.id) AS genreIds, + GROUP_CONCAT(DISTINCT u.userId) AS likedUserIds, + f.ratingId + FROM film f + LEFT JOIN filmGenre fg ON f.id = fg.filmId + LEFT JOIN genres g ON fg.genreId = g.id + LEFT JOIN likedUsers u ON f.id = u.filmId + WHERE f.id = ? + GROUP BY f.id + """; + + Film film; try { - jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); + film = jdbcTemplate.queryForObject(sqlQuery, (rs, rowNum) -> { + Film f = mapRowToFilm(rs, rowNum); // Передаем rowNum + + // Извлечение жанров + String[] genreIds = rs.getString("genreIds") != null ? rs.getString("genreIds").split(",") : new String[0]; + LinkedHashSet genres = new LinkedHashSet<>(); + for (String genreId : genreIds) { + genres.add(Long.valueOf(genreId)); + } + f.setGenres(genres); + + // Извлечение пользователей, которые лайкнули фильм + String[] likedUserIds = rs.getString("likedUserIds") != null ? rs.getString("likedUserIds").split(",") : new String[0]; + Set likedUsers = new HashSet<>(); + for (String userId : likedUserIds) { + likedUsers.add(Long.valueOf(userId)); + } + f.setLikedUsers(likedUsers); + + // Установка рейтинга + f.setMpa(rs.getLong("ratingId")); + + return f; + }, id); } catch (DataAccessException e) { - logAndThrowNotFoundException(id.toString(), ERROR_FILM_NOT_FOUND); + return null; // или выбросить исключение, если это необходимо } - Film film = jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); - String sqlQuery6 = "select filmId, userId from likedUsers where filmId = ?"; - Map> likedUsers = jdbcTemplate.query(sqlQuery6, new LikedUsersExtractor(), id); - String sqlQuery7 = "select filmId, genreId from filmGenre where filmId = ?"; - Map> filmGenre = jdbcTemplate.query(sqlQuery7, new FilmGenreExtractor(), id); - String sqlQuery8 = "select id, ratingId from film where id = ?"; - Map filmRating = jdbcTemplate.query(sqlQuery8, new FilmRatingExtractor(), id); - + Map genreMap = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); + Map ratingMap = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); - film.setLikedUsers(likedUsers.get(id)); - - film.setGenres(filmGenre.get(id)); - Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); - Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); - LinkedHashSet genres = new LinkedHashSet<>(); - if (!filmGenre.isEmpty()) { - for (Long g : filmGenre.get(id)) { - genres.add(Genre.of(g, genre.get(g))); - } + // Устанавливаем названия жанров + LinkedHashSet genreObjects = new LinkedHashSet<>(); + for (Long genreId : film.getGenres()) { + genreObjects.add(Genre.of(genreId, genreMap.get(genreId))); } - film.setMpa(filmRating.get(id)); - - return FilmResponse.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), Mpa.of(film.getMpa(), rating.get(film.getMpa())), genres); + // Возвращаем FilmResponse с двумя параметрами + return FilmResponse.of(film.getId(), film.getName(), film.getDescription(), + film.getReleaseDate(), film.getDuration(), + new HashSet<>(), Mpa.of(film.getMpa(), ratingMap.get(film.getMpa())), + genreObjects); } @Override - public FilmResponse create(@Valid Buffer buffer) { - log.info(LOG_CREATE_REQUEST); - validateBuffer(buffer); - - SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); - Long filmId = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); - - Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); - Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); - - LinkedHashSet genres = processGenres(buffer.getGenres(), filmId, genre); - updateFilmRating(buffer.getMpa(), filmId); - - return FilmResponse.of(filmId, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres); + public FilmResponse create(Buffer film) { + return null; } @Override From 4ab5358bccc2b6476806f9f51530c29a754aa4e8 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 01:30:46 +0500 Subject: [PATCH 087/118] =?UTF-8?q?=D0=BA=D0=BE=D1=88=D0=BC=D0=B0=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index f72b7d0..5412f5a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -150,17 +150,17 @@ public FilmResponse findById(Long id) { } String sqlQuery = """ - SELECT f.id, f.name, f.description, f.releaseDate, f.duration, - GROUP_CONCAT(DISTINCT g.id) AS genreIds, - GROUP_CONCAT(DISTINCT u.userId) AS likedUserIds, - f.ratingId + SELECT f.id, f.name, f.description, f.releaseDate, f.duration,\s + GROUP_CONCAT(DISTINCT g.id) AS genreIds,\s + GROUP_CONCAT(DISTINCT u.userId) AS likedUserIds,\s + f.ratingId\s FROM film f LEFT JOIN filmGenre fg ON f.id = fg.filmId LEFT JOIN genres g ON fg.genreId = g.id LEFT JOIN likedUsers u ON f.id = u.filmId WHERE f.id = ? GROUP BY f.id - """; + \s"""; Film film; try { From 9c5a915fdefc19083a102279e44ce00988de58ae Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 01:35:18 +0500 Subject: [PATCH 088/118] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D1=82=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/storage/film/FilmDbStorage.java | 109 ++++++++---------- 1 file changed, 48 insertions(+), 61 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 5412f5a..7ba033f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -7,6 +7,7 @@ import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; import org.springframework.stereotype.Repository; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; @@ -104,15 +105,15 @@ public Map extractData(ResultSet rs) throws SQLException { public List findAll() { log.info(LOG_GET_REQUEST); String sqlQuery = """ - SELECT f.id, f.name, f.description, f.releaseDate, f.duration, - GROUP_CONCAT(DISTINCT fg.genreId) AS genreIds, - GROUP_CONCAT(DISTINCT lu.userId) AS likedUserIds, - f.ratingId - FROM film f - LEFT JOIN filmGenre fg ON f.id = fg.filmId - LEFT JOIN likedUsers lu ON f.id = lu.filmId - GROUP BY f.id - """; + SELECT f.id, f.name, f.description, f.releaseDate, f.duration, + GROUP_CONCAT(DISTINCT fg.genreId) AS genreIds, + GROUP_CONCAT(DISTINCT lu.userId) AS likedUserIds, + f.ratingId + FROM film f + LEFT JOIN filmGenre fg ON f.id = fg.filmId + LEFT JOIN likedUsers lu ON f.id = lu.filmId + GROUP BY f.id + """; List films = jdbcTemplate.query(sqlQuery, (rs, rowNum) -> { Film film = mapRowToFilm(rs, rowNum); @@ -149,69 +150,55 @@ public FilmResponse findById(Long id) { logAndThrowConditionsNotMetException(ERROR_NULL_ID); } - String sqlQuery = """ - SELECT f.id, f.name, f.description, f.releaseDate, f.duration,\s - GROUP_CONCAT(DISTINCT g.id) AS genreIds,\s - GROUP_CONCAT(DISTINCT u.userId) AS likedUserIds,\s - f.ratingId\s - FROM film f - LEFT JOIN filmGenre fg ON f.id = fg.filmId - LEFT JOIN genres g ON fg.genreId = g.id - LEFT JOIN likedUsers u ON f.id = u.filmId - WHERE f.id = ? - GROUP BY f.id - \s"""; - - Film film; + String sqlQuery5 = "select id, name, description, releaseDate, duration from film where id = ?"; try { - film = jdbcTemplate.queryForObject(sqlQuery, (rs, rowNum) -> { - Film f = mapRowToFilm(rs, rowNum); // Передаем rowNum - - // Извлечение жанров - String[] genreIds = rs.getString("genreIds") != null ? rs.getString("genreIds").split(",") : new String[0]; - LinkedHashSet genres = new LinkedHashSet<>(); - for (String genreId : genreIds) { - genres.add(Long.valueOf(genreId)); - } - f.setGenres(genres); - - // Извлечение пользователей, которые лайкнули фильм - String[] likedUserIds = rs.getString("likedUserIds") != null ? rs.getString("likedUserIds").split(",") : new String[0]; - Set likedUsers = new HashSet<>(); - for (String userId : likedUserIds) { - likedUsers.add(Long.valueOf(userId)); - } - f.setLikedUsers(likedUsers); - - // Установка рейтинга - f.setMpa(rs.getLong("ratingId")); - - return f; - }, id); + jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); } catch (DataAccessException e) { + logAndThrowNotFoundException(id.toString(), ERROR_FILM_NOT_FOUND); - return null; // или выбросить исключение, если это необходимо } - Map genreMap = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); - Map ratingMap = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); + Film film = jdbcTemplate.queryForObject(sqlQuery5, this::mapRowToFilm, id); + String sqlQuery6 = "select filmId, userId from likedUsers where filmId = ?"; + Map> likedUsers = jdbcTemplate.query(sqlQuery6, new LikedUsersExtractor(), id); + String sqlQuery7 = "select filmId, genreId from filmGenre where filmId = ?"; + Map> filmGenre = jdbcTemplate.query(sqlQuery7, new FilmGenreExtractor(), id); + String sqlQuery8 = "select id, ratingId from film where id = ?"; + Map filmRating = jdbcTemplate.query(sqlQuery8, new FilmRatingExtractor(), id); + + + film.setLikedUsers(likedUsers.get(id)); - // Устанавливаем названия жанров - LinkedHashSet genreObjects = new LinkedHashSet<>(); - for (Long genreId : film.getGenres()) { - genreObjects.add(Genre.of(genreId, genreMap.get(genreId))); + film.setGenres(filmGenre.get(id)); + Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); + Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); + LinkedHashSet genres = new LinkedHashSet<>(); + if (!filmGenre.isEmpty()) { + for (Long g : filmGenre.get(id)) { + genres.add(Genre.of(g, genre.get(g))); + } } - // Возвращаем FilmResponse с двумя параметрами - return FilmResponse.of(film.getId(), film.getName(), film.getDescription(), - film.getReleaseDate(), film.getDuration(), - new HashSet<>(), Mpa.of(film.getMpa(), ratingMap.get(film.getMpa())), - genreObjects); + film.setMpa(filmRating.get(id)); + + return FilmResponse.of(film.getId(), film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), new HashSet<>(), Mpa.of(film.getMpa(), rating.get(film.getMpa())), genres); } @Override - public FilmResponse create(Buffer film) { - return null; + public FilmResponse create(@Valid Buffer buffer) { + log.info(LOG_CREATE_REQUEST); + validateBuffer(buffer); + + SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate).withTableName("film").usingGeneratedKeyColumns("id"); + Long filmId = simpleJdbcInsert.executeAndReturnKey(buffer.toMapBuffer()).longValue(); + + Map genre = jdbcTemplate.query(SQL_SELECT_GENRES, new GenreExtractor()); + Map rating = jdbcTemplate.query(SQL_SELECT_RATINGS, new RatingNameExtractor()); + + LinkedHashSet genres = processGenres(buffer.getGenres(), filmId, genre); + updateFilmRating(buffer.getMpa(), filmId); + + return FilmResponse.of(filmId, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres); } @Override From 98eab613fc800d060e2a7e940164b28396a2295a Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 02:01:09 +0500 Subject: [PATCH 089/118] =?UTF-8?q?=D0=BB=D0=B8=D0=BC=D0=B8=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/FilmService.java | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 3d3a7e1..089f48f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -80,22 +80,42 @@ public FilmResponse delLike(Long idUser, Long idFilm) { public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); - LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); + + if (count == null || count <= 0) { + throw new IllegalArgumentException("Count must be greater than zero."); + } + + String selectTopFilmsQueryWithLimit = selectTopFilmsQuery + " LIMIT ?"; + LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQueryWithLimit, new TopLikedUsersExtractor(), count); + LinkedHashSet films = new LinkedHashSet<>(); - if (likedUsers == null) { + if (likedUsers.isEmpty()) { log.error("Список фильмов с рейтингом пуст."); throw new NotFoundException("Список фильмов с рейтингом пуст."); } else { - LinkedHashSet genres = new LinkedHashSet<>(); - for (Long l : likedUsers.keySet()) { - Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); - if (!filmGenre.isEmpty()) { - for (Long g : filmGenre.get(filmStorage.findById(l).getId())) - genres.add(g); + for (Long filmId : likedUsers.keySet()) { + FilmResponse film = filmStorage.findById(filmId); + if (film != null) { + + Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), film.getId()); + assert filmGenre != null; + LinkedHashSet genres = filmGenre.getOrDefault(film.getId(), new LinkedHashSet<>()); + + // Create FilmResponse object + films.add(FilmResponse.of( + film.getId(), + film.getName(), + film.getDescription(), + film.getReleaseDate(), + film.getDuration(), + new HashSet<>(), // Assuming this is for liked users, adjust as necessary + film.getMpa(), + new LinkedHashSet<>() + )); } - films.add(FilmResponse.of(filmStorage.findById(l).getId(), filmStorage.findById(l).getName(), filmStorage.findById(l).getDescription(), filmStorage.findById(l).getReleaseDate(), filmStorage.findById(l).getDuration(), new HashSet<>(), filmStorage.findById(l).getMpa(), genres)); } } return films; } + } \ No newline at end of file From b5292b9549aaaee3ee69df4d5c9392c2b1cc11fb Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 02:16:45 +0500 Subject: [PATCH 090/118] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B1=D1=83=D0=B5?= =?UTF-8?q?=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/FilmService.java | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 089f48f..267e47e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -81,41 +81,41 @@ public FilmResponse delLike(Long idUser, Long idFilm) { public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); - if (count == null || count <= 0) { - throw new IllegalArgumentException("Count must be greater than zero."); - } - - String selectTopFilmsQueryWithLimit = selectTopFilmsQuery + " LIMIT ?"; - LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQueryWithLimit, new TopLikedUsersExtractor(), count); + // Изменяем запрос, чтобы использовать параметр count для ограничения результатов + String limitedSelectTopFilmsQuery = selectTopFilmsQuery + " LIMIT " + count; + LinkedHashMap likedUsers = jdbcTemplate.query(limitedSelectTopFilmsQuery, new TopLikedUsersExtractor()); LinkedHashSet films = new LinkedHashSet<>(); - if (likedUsers.isEmpty()) { + + if (likedUsers == null || likedUsers.isEmpty()) { log.error("Список фильмов с рейтингом пуст."); throw new NotFoundException("Список фильмов с рейтингом пуст."); } else { - for (Long filmId : likedUsers.keySet()) { - FilmResponse film = filmStorage.findById(filmId); - if (film != null) { + for (Long l : likedUsers.keySet()) { + LinkedHashSet genres = new LinkedHashSet<>(); + Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, + new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); - Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), film.getId()); - assert filmGenre != null; - LinkedHashSet genres = filmGenre.getOrDefault(film.getId(), new LinkedHashSet<>()); - - // Create FilmResponse object - films.add(FilmResponse.of( - film.getId(), - film.getName(), - film.getDescription(), - film.getReleaseDate(), - film.getDuration(), - new HashSet<>(), // Assuming this is for liked users, adjust as necessary - film.getMpa(), - new LinkedHashSet<>() - )); + if (!filmGenre.isEmpty()) { + for (Long genreId : filmGenre.get(filmStorage.findById(l).getId())) { + String genreName = jdbcTemplate.queryForObject("SELECT name FROM genres WHERE id = ?", + new Object[]{genreId}, String.class); + genres.add(Genre.of(genreId, genreName)); // Создаем жанр с id и name + } } + + films.add(FilmResponse.of( + filmStorage.findById(l).getId(), + filmStorage.findById(l).getName(), + filmStorage.findById(l).getDescription(), + filmStorage.findById(l).getReleaseDate(), + filmStorage.findById(l).getDuration(), + new HashSet<>(), + filmStorage.findById(l).getMpa(), + genres + )); } } return films; } - } \ No newline at end of file From 80e7f120d369cb3d0378a16da5e69191e07f1c11 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 02:21:22 +0500 Subject: [PATCH 091/118] =?UTF-8?q?=D0=BE=D0=BF=D1=8F=D1=82=D1=8C=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B1=D1=83=D0=B5=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/FilmService.java | 72 ++++++++++++------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 267e47e..e119322 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -81,41 +81,61 @@ public FilmResponse delLike(Long idUser, Long idFilm) { public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); - // Изменяем запрос, чтобы использовать параметр count для ограничения результатов - String limitedSelectTopFilmsQuery = selectTopFilmsQuery + " LIMIT " + count; + if (count == null || count <= 0) { + throw new IllegalArgumentException("Count must be greater than zero."); + } - LinkedHashMap likedUsers = jdbcTemplate.query(limitedSelectTopFilmsQuery, new TopLikedUsersExtractor()); - LinkedHashSet films = new LinkedHashSet<>(); + // Используем параметризованный запрос для безопасности + String limitedSelectTopFilmsQuery = selectTopFilmsQuery + " LIMIT ?"; + LinkedHashMap likedUsers = jdbcTemplate.query(limitedSelectTopFilmsQuery, new TopLikedUsersExtractor(), count); + LinkedHashSet films = new LinkedHashSet<>(); if (likedUsers == null || likedUsers.isEmpty()) { log.error("Список фильмов с рейтингом пуст."); throw new NotFoundException("Список фильмов с рейтингом пуст."); - } else { - for (Long l : likedUsers.keySet()) { - LinkedHashSet genres = new LinkedHashSet<>(); - Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, - new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); - - if (!filmGenre.isEmpty()) { - for (Long genreId : filmGenre.get(filmStorage.findById(l).getId())) { - String genreName = jdbcTemplate.queryForObject("SELECT name FROM genres WHERE id = ?", - new Object[]{genreId}, String.class); - genres.add(Genre.of(genreId, genreName)); // Создаем жанр с id и name + } + + // Получаем все жанры за один запрос + Map allGenres = new HashMap<>(); + jdbcTemplate.query("SELECT id, name FROM genres", rs -> { + allGenres.put(rs.getLong("id"), Genre.of(rs.getLong("id"), rs.getString("name"))); + }); + + for (Long filmId : likedUsers.keySet()) { + FilmResponse film = filmStorage.findById(filmId); + if (film == null) { + log.warn("Фильм с id {} не найден.", filmId); + continue; + } + + // Получаем жанры для текущего фильма + Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, + new FilmDbStorage.FilmGenreExtractor(), film.getId()); + + LinkedHashSet genres = new LinkedHashSet<>(); + if (!filmGenre.isEmpty()) { + for (Long genreId : filmGenre.get(film.getId())) { + Genre genre = allGenres.get(genreId); + if (genre != null) { + genres.add(genre); } } - - films.add(FilmResponse.of( - filmStorage.findById(l).getId(), - filmStorage.findById(l).getName(), - filmStorage.findById(l).getDescription(), - filmStorage.findById(l).getReleaseDate(), - filmStorage.findById(l).getDuration(), - new HashSet<>(), - filmStorage.findById(l).getMpa(), - genres - )); } + + // Создаем объект FilmResponse + films.add(FilmResponse.of( + film.getId(), + film.getName(), + film.getDescription(), + film.getReleaseDate(), + film.getDuration(), + new HashSet<>(), // Предполагаем, что это для liked users, настройте при необходимости + film.getMpa(), + genres + )); } + + log.info("Найдено фильмов: {}", films.size()); return films; } } \ No newline at end of file From 313816f10ec19eba3b46ba1e72988625f36d3b10 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 02:29:33 +0500 Subject: [PATCH 092/118] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D1=82=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/FilmService.java | 60 ++++--------------- 1 file changed, 10 insertions(+), 50 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index e119322..3d3a7e1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -80,62 +80,22 @@ public FilmResponse delLike(Long idUser, Long idFilm) { public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); - - if (count == null || count <= 0) { - throw new IllegalArgumentException("Count must be greater than zero."); - } - - // Используем параметризованный запрос для безопасности - String limitedSelectTopFilmsQuery = selectTopFilmsQuery + " LIMIT ?"; - LinkedHashMap likedUsers = jdbcTemplate.query(limitedSelectTopFilmsQuery, new TopLikedUsersExtractor(), count); - + LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); LinkedHashSet films = new LinkedHashSet<>(); - if (likedUsers == null || likedUsers.isEmpty()) { + if (likedUsers == null) { log.error("Список фильмов с рейтингом пуст."); throw new NotFoundException("Список фильмов с рейтингом пуст."); - } - - // Получаем все жанры за один запрос - Map allGenres = new HashMap<>(); - jdbcTemplate.query("SELECT id, name FROM genres", rs -> { - allGenres.put(rs.getLong("id"), Genre.of(rs.getLong("id"), rs.getString("name"))); - }); - - for (Long filmId : likedUsers.keySet()) { - FilmResponse film = filmStorage.findById(filmId); - if (film == null) { - log.warn("Фильм с id {} не найден.", filmId); - continue; - } - - // Получаем жанры для текущего фильма - Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, - new FilmDbStorage.FilmGenreExtractor(), film.getId()); - - LinkedHashSet genres = new LinkedHashSet<>(); - if (!filmGenre.isEmpty()) { - for (Long genreId : filmGenre.get(film.getId())) { - Genre genre = allGenres.get(genreId); - if (genre != null) { - genres.add(genre); - } + } else { + LinkedHashSet genres = new LinkedHashSet<>(); + for (Long l : likedUsers.keySet()) { + Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); + if (!filmGenre.isEmpty()) { + for (Long g : filmGenre.get(filmStorage.findById(l).getId())) + genres.add(g); } + films.add(FilmResponse.of(filmStorage.findById(l).getId(), filmStorage.findById(l).getName(), filmStorage.findById(l).getDescription(), filmStorage.findById(l).getReleaseDate(), filmStorage.findById(l).getDuration(), new HashSet<>(), filmStorage.findById(l).getMpa(), genres)); } - - // Создаем объект FilmResponse - films.add(FilmResponse.of( - film.getId(), - film.getName(), - film.getDescription(), - film.getReleaseDate(), - film.getDuration(), - new HashSet<>(), // Предполагаем, что это для liked users, настройте при необходимости - film.getMpa(), - genres - )); } - - log.info("Найдено фильмов: {}", films.size()); return films; } } \ No newline at end of file From da5e701b4a802eecb81b93fad9165066606dbba4 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 15:44:00 +0500 Subject: [PATCH 093/118] =?UTF-8?q?=D0=B8=D0=B6=D0=B5=D0=BA=D1=82=D1=8E=20?= =?UTF-8?q?=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20=D0=BA=D0=BE=D0=BD=D1=81=D1=82?= =?UTF-8?q?=D1=80=D1=83=D0=BA=D1=82=D0=BE=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/service/FilmService.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 3d3a7e1..083fc31 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -2,13 +2,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; -import ru.yandex.practicum.filmorate.model.*; +import ru.yandex.practicum.filmorate.model.FilmResponse; import ru.yandex.practicum.filmorate.storage.film.FilmDbStorage; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; @@ -17,13 +15,11 @@ @Service @Slf4j(topic = "TRACE") -@ConfigurationPropertiesScan @RequiredArgsConstructor public class FilmService implements FilmInterface { - @Autowired - UserStorage userStorage; - @Autowired - FilmStorage filmStorage; + + private final UserStorage userStorage; + private final FilmStorage filmStorage; private final JdbcTemplate jdbcTemplate; // SQL-запросы @@ -33,7 +29,6 @@ public class FilmService implements FilmInterface { private final String deleteLikeQuery = "delete from likedUsers where filmId = ? and userId = ?"; private final String selectTopFilmsQuery = "select f.id as name, COUNT(l.userId) as coun from likedUsers as l LEFT OUTER JOIN film AS f ON l.filmId = f.id GROUP BY f.name ORDER BY COUNT(l.userId) DESC LIMIT 10"; - @Override public FilmResponse addLike(Long idUser, Long idFilm) { log.info("Обработка Post-запроса..."); From f738fa608d53c3ce58bea40bf5189631091c59a8 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 15:55:30 +0500 Subject: [PATCH 094/118] =?UTF-8?q?=D1=81=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB?= =?UTF-8?q?=D0=B0=20=D0=B1=D0=B8=D0=BD=D1=8B=20=D1=81=20=D0=BC=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8C=D0=BA=D0=BE=D0=B9=20=D0=B1=D1=83=D0=BA=D0=B2?= =?UTF-8?q?=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/controller/FilmController.java | 2 +- .../yandex/practicum/filmorate/controller/UserController.java | 2 +- .../java/ru/yandex/practicum/filmorate/service/UserService.java | 2 +- .../yandex/practicum/filmorate/storage/user/UserDbStorage.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 6f30a45..71b17e3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -31,7 +31,7 @@ public class FilmController { @Autowired public FilmController( @Qualifier("FilmDbStorage") FilmStorage filmStorage, - @Qualifier("UserDbStorage") UserStorage userStorage, + @Qualifier("userDbStorage") UserStorage userStorage, FilmInterface filmInterface ) { this.filmStorage = filmStorage; diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index 2424ca6..fde07c8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -22,7 +22,7 @@ public class UserController { private static final String FRIEND_ID_PATH = FRIENDS_PATH + "/{friendId}"; private static final String COMMON_FRIENDS_PATH = USER_ID_PATH + "/friends/common/{otherId}"; - @Qualifier("UserDbStorage") + @Qualifier("userDbStorage") private final UserStorage userStorage; private final UserInterface userInterface; diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 9a39c5a..5f92e12 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -36,7 +36,7 @@ public class UserService implements UserInterface { private static final String ERROR_USER_NOT_FOUND = "Пользователь с данным идентификатором отсутствует в базе"; @Autowired - @Qualifier("UserDbStorage") + @Qualifier("userDbStorage") private final UserStorage userStorage; private final JdbcTemplate jdbcTemplate; diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 671c5b4..d03133b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -23,7 +23,7 @@ @Repository @RequiredArgsConstructor @Slf4j(topic = "TRACE") -@Qualifier("UserDbStorage") +@Qualifier("userDbStorage") public class UserDbStorage implements UserStorage { private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); From f0e464d2b956e9afe5edcb5c043e06d7973608d7 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 15:56:42 +0500 Subject: [PATCH 095/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D0=BE=D1=82=D0=B0=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/controller/FilmController.java | 7 ++++--- .../practicum/filmorate/controller/UserController.java | 1 - .../ru/yandex/practicum/filmorate/service/UserService.java | 1 - .../practicum/filmorate/storage/user/UserDbStorage.java | 1 - 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 71b17e3..4eb0c76 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -6,7 +6,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; - import ru.yandex.practicum.filmorate.model.Buffer; +import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmResponse; import ru.yandex.practicum.filmorate.service.FilmInterface; @@ -30,8 +30,9 @@ public class FilmController { @Autowired public FilmController( - @Qualifier("FilmDbStorage") FilmStorage filmStorage, - @Qualifier("userDbStorage") UserStorage userStorage, + @Qualifier("FilmDbStorage") + FilmStorage filmStorage, + UserStorage userStorage, FilmInterface filmInterface ) { this.filmStorage = filmStorage; diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index fde07c8..a8d1b03 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -22,7 +22,6 @@ public class UserController { private static final String FRIEND_ID_PATH = FRIENDS_PATH + "/{friendId}"; private static final String COMMON_FRIENDS_PATH = USER_ID_PATH + "/friends/common/{otherId}"; - @Qualifier("userDbStorage") private final UserStorage userStorage; private final UserInterface userInterface; diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 5f92e12..528d4e3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -36,7 +36,6 @@ public class UserService implements UserInterface { private static final String ERROR_USER_NOT_FOUND = "Пользователь с данным идентификатором отсутствует в базе"; @Autowired - @Qualifier("userDbStorage") private final UserStorage userStorage; private final JdbcTemplate jdbcTemplate; diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index d03133b..0bfcb3f 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -23,7 +23,6 @@ @Repository @RequiredArgsConstructor @Slf4j(topic = "TRACE") -@Qualifier("userDbStorage") public class UserDbStorage implements UserStorage { private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); From 87393510fd9ac7f2ac9fd37269fda64b047d92db Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 15:59:37 +0500 Subject: [PATCH 096/118] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=D1=8C=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/controller/UserController.java | 1 - .../java/ru/yandex/practicum/filmorate/service/UserService.java | 1 - .../yandex/practicum/filmorate/storage/user/UserDbStorage.java | 1 - 3 files changed, 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index a8d1b03..707d71a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -2,7 +2,6 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.model.User; diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 528d4e3..a53146c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -3,7 +3,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java index 0bfcb3f..690f0f3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorage.java @@ -3,7 +3,6 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; From 3f33f52d01a58848f44e27b95224c36c6cdfed1c Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 16:13:14 +0500 Subject: [PATCH 097/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D0=BE=D1=82=D0=B0=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ru/yandex/practicum/filmorate/service/UserService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index a53146c..2563e36 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -34,7 +34,6 @@ public class UserService implements UserInterface { private static final String ERROR_FRIEND_ALREADY_ADDED = "Пользователь с id %d уже добавлен в друзья"; private static final String ERROR_USER_NOT_FOUND = "Пользователь с данным идентификатором отсутствует в базе"; - @Autowired private final UserStorage userStorage; private final JdbcTemplate jdbcTemplate; From 490817c910091068450fb4042716959d738e8054 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 16:15:22 +0500 Subject: [PATCH 098/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=B5=D1=89=D0=B5=20=D0=BD=D0=B5=D0=BD=D1=83=D0=B6=D0=BD=D1=8B?= =?UTF-8?q?=D0=B5=20=D0=B0=D0=BD=D0=BD=D0=BE=D1=82=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/service/UserService.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 2563e36..ae96394 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -2,8 +2,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; @@ -18,7 +16,6 @@ @Service @Slf4j(topic = "TRACE") -@ConfigurationPropertiesScan @RequiredArgsConstructor public class UserService implements UserInterface { From 0d461441d91aab92a4f8783536fd3bf73e128762 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 16:19:28 +0500 Subject: [PATCH 099/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D0=BE=D1=82=D0=B0=D1=86=D0=B8=D1=8E=20@Quali?= =?UTF-8?q?fier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/controller/FilmController.java | 2 -- .../yandex/practicum/filmorate/storage/film/FilmDbStorage.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 4eb0c76..b0a6080 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.model.Buffer; @@ -30,7 +29,6 @@ public class FilmController { @Autowired public FilmController( - @Qualifier("FilmDbStorage") FilmStorage filmStorage, UserStorage userStorage, FilmInterface filmInterface diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 7ba033f..7c2330e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -3,7 +3,6 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; @@ -24,7 +23,6 @@ @Repository @RequiredArgsConstructor @Slf4j(topic = "TRACE") -@Qualifier("FilmDbStorage") public class FilmDbStorage implements FilmStorage { //SQL-запросы From 97c56325446dec5f08819a10cf4789caeb1b0ccf Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 16:28:52 +0500 Subject: [PATCH 100/118] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D1=83=20=D0=B0=D0=B9?= =?UTF-8?q?=D0=B4=D0=B8,=20=D1=81=D0=BA=D0=BE=D1=80=D0=B5=D0=B5=20=D0=B2?= =?UTF-8?q?=D1=81=D0=B5=D0=B3=D0=BE,=20=D0=BF=D0=BE=D0=BB=D0=B5=D1=82?= =?UTF-8?q?=D1=8F=D1=82=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/storage/film/FilmDbStorage.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index 7c2330e..f1785c8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -257,7 +257,7 @@ private LinkedHashSet processGenres(List genres, Long filmId, Map for (String genreIdStr : genres) { Long genreId = Long.parseLong(genreIdStr); - if (!(genreId > 0 && genreId < 7)) { + if (!genreMap.containsKey(genreId)) { logAndThrowNotFoundException(genreId.toString(), ERROR_INVALID_GENRE); } jdbcTemplate.update(SQL_INSERT_FILM_GENRE, filmId, genreId); @@ -266,6 +266,7 @@ private LinkedHashSet processGenres(List genres, Long filmId, Map return result; } + private void updateFilmRating(Long mpaId, Long filmId) { jdbcTemplate.update(SQL_UPDATE_FILM_RATING, mpaId, filmId); } From 7f213ed0d696774a0b76a83f163d5f6614c2cfa0 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 17:15:26 +0500 Subject: [PATCH 101/118] =?UTF-8?q?=D0=BF=D1=8B=D1=82=D0=B0=D1=8E=D1=81?= =?UTF-8?q?=D1=8C=20=D0=B2=D0=BD=D0=B5=D1=81=D1=82=D0=B8=20count=20=D0=B2?= =?UTF-8?q?=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/FilmService.java | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 083fc31..f7b873e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -7,6 +7,7 @@ import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.FilmResponse; +import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.storage.film.FilmDbStorage; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; @@ -75,20 +76,39 @@ public FilmResponse delLike(Long idUser, Long idFilm) { public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); - LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); + + String limitedSelectTopFilmsQuery = selectTopFilmsQuery + " LIMIT " + count; + + LinkedHashMap likedUsers = jdbcTemplate.query(limitedSelectTopFilmsQuery, new TopLikedUsersExtractor()); LinkedHashSet films = new LinkedHashSet<>(); - if (likedUsers == null) { + + if (likedUsers == null || likedUsers.isEmpty()) { log.error("Список фильмов с рейтингом пуст."); throw new NotFoundException("Список фильмов с рейтингом пуст."); } else { - LinkedHashSet genres = new LinkedHashSet<>(); for (Long l : likedUsers.keySet()) { - Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); + LinkedHashSet genres = new LinkedHashSet<>(); + Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, + new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); + if (!filmGenre.isEmpty()) { - for (Long g : filmGenre.get(filmStorage.findById(l).getId())) - genres.add(g); + for (Long genreId : filmGenre.get(filmStorage.findById(l).getId())) { + String genreName = jdbcTemplate.queryForObject("SELECT name FROM genres WHERE id = ?", + new Object[]{genreId}, String.class); + genres.add(Genre.of(genreId, genreName)); // Создаем жанр с id и name + } } - films.add(FilmResponse.of(filmStorage.findById(l).getId(), filmStorage.findById(l).getName(), filmStorage.findById(l).getDescription(), filmStorage.findById(l).getReleaseDate(), filmStorage.findById(l).getDuration(), new HashSet<>(), filmStorage.findById(l).getMpa(), genres)); + + films.add(FilmResponse.of( + filmStorage.findById(l).getId(), + filmStorage.findById(l).getName(), + filmStorage.findById(l).getDescription(), + filmStorage.findById(l).getReleaseDate(), + filmStorage.findById(l).getDuration(), + new HashSet<>(), + filmStorage.findById(l).getMpa(), + genres + )); } } return films; From b5a841d966039b4e3754a6a8a9ad8b80111bf1f5 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 17:32:28 +0500 Subject: [PATCH 102/118] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D1=82=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/FilmService.java | 34 ++++--------------- 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index f7b873e..083fc31 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -7,7 +7,6 @@ import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.FilmResponse; -import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.storage.film.FilmDbStorage; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; @@ -76,39 +75,20 @@ public FilmResponse delLike(Long idUser, Long idFilm) { public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); - - String limitedSelectTopFilmsQuery = selectTopFilmsQuery + " LIMIT " + count; - - LinkedHashMap likedUsers = jdbcTemplate.query(limitedSelectTopFilmsQuery, new TopLikedUsersExtractor()); + LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); LinkedHashSet films = new LinkedHashSet<>(); - - if (likedUsers == null || likedUsers.isEmpty()) { + if (likedUsers == null) { log.error("Список фильмов с рейтингом пуст."); throw new NotFoundException("Список фильмов с рейтингом пуст."); } else { + LinkedHashSet genres = new LinkedHashSet<>(); for (Long l : likedUsers.keySet()) { - LinkedHashSet genres = new LinkedHashSet<>(); - Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, - new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); - + Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); if (!filmGenre.isEmpty()) { - for (Long genreId : filmGenre.get(filmStorage.findById(l).getId())) { - String genreName = jdbcTemplate.queryForObject("SELECT name FROM genres WHERE id = ?", - new Object[]{genreId}, String.class); - genres.add(Genre.of(genreId, genreName)); // Создаем жанр с id и name - } + for (Long g : filmGenre.get(filmStorage.findById(l).getId())) + genres.add(g); } - - films.add(FilmResponse.of( - filmStorage.findById(l).getId(), - filmStorage.findById(l).getName(), - filmStorage.findById(l).getDescription(), - filmStorage.findById(l).getReleaseDate(), - filmStorage.findById(l).getDuration(), - new HashSet<>(), - filmStorage.findById(l).getMpa(), - genres - )); + films.add(FilmResponse.of(filmStorage.findById(l).getId(), filmStorage.findById(l).getName(), filmStorage.findById(l).getDescription(), filmStorage.findById(l).getReleaseDate(), filmStorage.findById(l).getDuration(), new HashSet<>(), filmStorage.findById(l).getMpa(), genres)); } } return films; From 29db07728260ba7881693bf72518f2455f2b44c3 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 17:39:23 +0500 Subject: [PATCH 103/118] =?UTF-8?q?=D0=B8=D0=B7=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=D1=81=D1=8C=20=D0=BE=D1=82=20=D0=BB=D0=B8=D1=88?= =?UTF-8?q?=D0=BD=D0=B5=D0=B3=D0=BE=20=D0=BF=D0=B0=D1=80=D1=81=D0=B8=D0=BD?= =?UTF-8?q?=D0=B3=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 59 ++----------------- 1 file changed, 6 insertions(+), 53 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index b0a6080..ffb4f58 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,6 +1,5 @@ package ru.yandex.practicum.filmorate.controller; -import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -12,17 +11,13 @@ import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.LinkedHashSet; +import java.util.List; @RestController @RequestMapping("/films") public class FilmController { - private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - private static final String DEFAULT_GENRE = "нет жанра"; - private final FilmStorage filmStorage; private final UserStorage userStorage; private final FilmInterface filmInterface; @@ -50,15 +45,13 @@ public FilmResponse findById(@PathVariable("id") Long id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmResponse create(@Valid @RequestBody ObjectNode objectNode) { - Buffer buffer = parseObjectNodeToBuffer(objectNode); - return filmStorage.create(buffer); + public FilmResponse create(@Valid @RequestBody Buffer film) { + return filmStorage.create(film); } @PutMapping - public FilmResponse update(@Valid @RequestBody ObjectNode objectNode) { - Buffer buffer = parseObjectNodeToBuffer(objectNode); - return filmStorage.update(buffer); + public FilmResponse update(@Valid @RequestBody Buffer film) { + return filmStorage.update(film); } @PutMapping("/{id}/like/{userId}") @@ -75,44 +68,4 @@ public FilmResponse delLike(@Valid @PathVariable("id") Long id, @PathVariable("u public LinkedHashSet viewRating(@RequestParam(defaultValue = "10") Long count) { return filmInterface.viewRating(count); } - - /** - * преобразует json объект в объект Buffer - * - * @param objectNode json объект - * @return объект Buffer - */ - private Buffer parseObjectNodeToBuffer(ObjectNode objectNode) { - Long id = objectNode.has("id") ? objectNode.get("id").asLong() : 0L; - String name = objectNode.get("name").asText(); - String description = objectNode.get("description").asText(); - String releaseDate = objectNode.get("releaseDate").asText(); - Integer duration = objectNode.get("duration").asInt(); - List mpa = objectNode.get("mpa").findValuesAsText("id"); - List genres = extractGenresFromObjectNode(objectNode); - - return Buffer.of( - id, - name, - description, - LocalDate.parse(releaseDate, DATE_FORMATTER), - duration, - genres, - Long.valueOf(mpa.get(0)) - ); - } - - /** - * извлекает список жанров из json объекта - * - * @param objectNode json объект - * @return список жанров - */ - private List extractGenresFromObjectNode(ObjectNode objectNode) { - try { - return objectNode.get("genres").findValuesAsText("id"); - } catch (NullPointerException e) { - return List.of(DEFAULT_GENRE); - } - } } \ No newline at end of file From d716acbc453778c9579688edcb28cebb92280d92 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 17:39:57 +0500 Subject: [PATCH 104/118] =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B9=20?= =?UTF-8?q?=D0=BF=D0=B0=D1=80=D1=81=D0=B8=D0=BD=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/controller/FilmController.java | 4 ++-- .../filmorate/storage/film/FilmDbStorage.java | 10 +++++++++- .../practicum/filmorate/storage/film/FilmStorage.java | 4 ++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index ffb4f58..3638ece 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -45,12 +45,12 @@ public FilmResponse findById(@PathVariable("id") Long id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmResponse create(@Valid @RequestBody Buffer film) { + public FilmResponse create(@Valid @RequestBody Film film) { return filmStorage.create(film); } @PutMapping - public FilmResponse update(@Valid @RequestBody Buffer film) { + public FilmResponse update(@Valid @RequestBody Film film) { return filmStorage.update(film); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index f1785c8..ba79066 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -183,6 +183,15 @@ public FilmResponse findById(Long id) { } @Override + public FilmResponse create(Film film) { + return null; + } + + @Override + public FilmResponse update(Film newFilm) { + return null; + } + public FilmResponse create(@Valid Buffer buffer) { log.info(LOG_CREATE_REQUEST); validateBuffer(buffer); @@ -199,7 +208,6 @@ public FilmResponse create(@Valid Buffer buffer) { return FilmResponse.of(filmId, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres); } - @Override public FilmResponse update(@Valid Buffer newFilm) { log.info(LOG_UPDATE_REQUEST); if (newFilm.getId() == null) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java index 9b12145..86f851c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java @@ -12,7 +12,7 @@ public interface FilmStorage { FilmResponse findById(Long id); - FilmResponse create(Buffer film); + FilmResponse create(Film film); - FilmResponse update(Buffer newFilm); + FilmResponse update(Film newFilm); } \ No newline at end of file From 06af9ea12cb5658dc53660b40e1a37d7bc433613 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 17:42:05 +0500 Subject: [PATCH 105/118] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/controller/FilmController.java | 1 - .../ru/yandex/practicum/filmorate/storage/film/FilmStorage.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 3638ece..67aaf36 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -4,7 +4,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; -import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmResponse; import ru.yandex.practicum.filmorate.service.FilmInterface; diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java index 86f851c..9000af3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java @@ -1,6 +1,5 @@ package ru.yandex.practicum.filmorate.storage.film; -import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmResponse; From bc332bd1a4e8c280ba65255e40a344befa4d195b Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 17:47:04 +0500 Subject: [PATCH 106/118] =?UTF-8?q?=D0=BE=D0=BF=D1=8F=D1=82=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practicum/filmorate/controller/FilmController.java | 5 +++-- .../filmorate/storage/film/FilmDbStorage.java | 10 +--------- .../practicum/filmorate/storage/film/FilmStorage.java | 5 +++-- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 67aaf36..ffb4f58 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmResponse; import ru.yandex.practicum.filmorate.service.FilmInterface; @@ -44,12 +45,12 @@ public FilmResponse findById(@PathVariable("id") Long id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmResponse create(@Valid @RequestBody Film film) { + public FilmResponse create(@Valid @RequestBody Buffer film) { return filmStorage.create(film); } @PutMapping - public FilmResponse update(@Valid @RequestBody Film film) { + public FilmResponse update(@Valid @RequestBody Buffer film) { return filmStorage.update(film); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index ba79066..f1785c8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -183,15 +183,6 @@ public FilmResponse findById(Long id) { } @Override - public FilmResponse create(Film film) { - return null; - } - - @Override - public FilmResponse update(Film newFilm) { - return null; - } - public FilmResponse create(@Valid Buffer buffer) { log.info(LOG_CREATE_REQUEST); validateBuffer(buffer); @@ -208,6 +199,7 @@ public FilmResponse create(@Valid Buffer buffer) { return FilmResponse.of(filmId, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres); } + @Override public FilmResponse update(@Valid Buffer newFilm) { log.info(LOG_UPDATE_REQUEST); if (newFilm.getId() == null) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java index 9000af3..9b12145 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.storage.film; +import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmResponse; @@ -11,7 +12,7 @@ public interface FilmStorage { FilmResponse findById(Long id); - FilmResponse create(Film film); + FilmResponse create(Buffer film); - FilmResponse update(Film newFilm); + FilmResponse update(Buffer newFilm); } \ No newline at end of file From 2a32abc923b03210960859cced21bb0934f53487 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 17:52:52 +0500 Subject: [PATCH 107/118] =?UTF-8?q?=D0=BF=D0=B0=D1=80=D1=81=D0=B8=D0=BC=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=BF=D1=80=D1=8F=D0=BC=D1=83=D1=8E=20=D1=87=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B7=20buffer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 8 ++++---- .../ru/yandex/practicum/filmorate/model/Buffer.java | 13 ++++++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index ffb4f58..731ddc2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -45,13 +45,13 @@ public FilmResponse findById(@PathVariable("id") Long id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmResponse create(@Valid @RequestBody Buffer film) { - return filmStorage.create(film); + public FilmResponse create(@Valid @RequestBody Buffer buffer) { + return filmStorage.create(buffer); } @PutMapping - public FilmResponse update(@Valid @RequestBody Buffer film) { - return filmStorage.update(film); + public FilmResponse update(@Valid @RequestBody Buffer buffer) { + return filmStorage.update(buffer); } @PutMapping("/{id}/like/{userId}") diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Buffer.java b/src/main/java/ru/yandex/practicum/filmorate/model/Buffer.java index 97ce14b..287b79d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Buffer.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Buffer.java @@ -3,29 +3,36 @@ import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import jdk.jfr.Description; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import java.time.LocalDate; -import java.util.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; @Data @Builder @AllArgsConstructor(staticName = "of") public class Buffer { private Long id; + @NotNull @NotBlank private String name; - @Description("New film update description") + private String description; + @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate releaseDate; + @NotNull private Integer duration; + private List genres; + private Long mpa; public Map toMapBuffer() { From 798bcba66b320bf5a60535dd32954bf5bcedf681 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 18:04:28 +0500 Subject: [PATCH 108/118] =?UTF-8?q?=D0=B0=D0=B0=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 40 ++++++++++++++++--- .../practicum/filmorate/model/Buffer.java | 13 ++---- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 731ddc2..d1b141d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -5,19 +5,23 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.model.Buffer; +import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmResponse; import ru.yandex.practicum.filmorate.service.FilmInterface; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.util.LinkedHashSet; -import java.util.List; +import java.time.format.DateTimeFormatter; +import java.util.*; @RestController @RequestMapping("/films") public class FilmController { + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static final String DEFAULT_GENRE = "нет жанра"; + private final FilmStorage filmStorage; private final UserStorage userStorage; private final FilmInterface filmInterface; @@ -45,12 +49,14 @@ public FilmResponse findById(@PathVariable("id") Long id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmResponse create(@Valid @RequestBody Buffer buffer) { + public FilmResponse create(@Valid @RequestBody FilmResponse filmRequest) { + Buffer buffer = parseFilmRequestToBuffer(filmRequest); return filmStorage.create(buffer); } @PutMapping - public FilmResponse update(@Valid @RequestBody Buffer buffer) { + public FilmResponse update(@Valid @RequestBody FilmResponse filmRequest) { + Buffer buffer = parseFilmRequestToBuffer(filmRequest); return filmStorage.update(buffer); } @@ -68,4 +74,28 @@ public FilmResponse delLike(@Valid @PathVariable("id") Long id, @PathVariable("u public LinkedHashSet viewRating(@RequestParam(defaultValue = "10") Long count) { return filmInterface.viewRating(count); } -} \ No newline at end of file + + /** + * преобразует FilmRequest в объект Buffer + * + * @param filmRequest объект FilmRequest + * @return объект Buffer + */ + private Buffer parseFilmRequestToBuffer(FilmResponse filmRequest) { + List genreIds = filmRequest.getGenres().stream() + .map(Genre::getId) // Получаем id каждого жанра + .map(String::valueOf) // Преобразуем Long в String + .toList(); // Собираем в List + + return Buffer.of( + filmRequest.getId(), + filmRequest.getName(), + filmRequest.getDescription(), + filmRequest.getReleaseDate(), + filmRequest.getDuration(), + genreIds, // Теперь это List + filmRequest.getMpa().getId() + ); + } + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Buffer.java b/src/main/java/ru/yandex/practicum/filmorate/model/Buffer.java index 287b79d..97ce14b 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Buffer.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Buffer.java @@ -3,36 +3,29 @@ import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import jdk.jfr.Description; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import java.time.LocalDate; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; @Data @Builder @AllArgsConstructor(staticName = "of") public class Buffer { private Long id; - @NotNull @NotBlank private String name; - + @Description("New film update description") private String description; - @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate releaseDate; - @NotNull private Integer duration; - private List genres; - private Long mpa; public Map toMapBuffer() { From da954138c8bfec255b6ff499d6c9e9284487825c Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 18:13:57 +0500 Subject: [PATCH 109/118] .... --- .../filmorate/controller/FilmController.java | 45 +++---------------- .../filmorate/storage/film/FilmDbStorage.java | 10 ++++- .../filmorate/storage/film/FilmStorage.java | 4 +- 3 files changed, 18 insertions(+), 41 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index d1b141d..67aaf36 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -4,24 +4,19 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; -import ru.yandex.practicum.filmorate.model.Buffer; -import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmResponse; import ru.yandex.practicum.filmorate.service.FilmInterface; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.LinkedHashSet; +import java.util.List; @RestController @RequestMapping("/films") public class FilmController { - private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - private static final String DEFAULT_GENRE = "нет жанра"; - private final FilmStorage filmStorage; private final UserStorage userStorage; private final FilmInterface filmInterface; @@ -49,15 +44,13 @@ public FilmResponse findById(@PathVariable("id") Long id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmResponse create(@Valid @RequestBody FilmResponse filmRequest) { - Buffer buffer = parseFilmRequestToBuffer(filmRequest); - return filmStorage.create(buffer); + public FilmResponse create(@Valid @RequestBody Film film) { + return filmStorage.create(film); } @PutMapping - public FilmResponse update(@Valid @RequestBody FilmResponse filmRequest) { - Buffer buffer = parseFilmRequestToBuffer(filmRequest); - return filmStorage.update(buffer); + public FilmResponse update(@Valid @RequestBody Film film) { + return filmStorage.update(film); } @PutMapping("/{id}/like/{userId}") @@ -74,28 +67,4 @@ public FilmResponse delLike(@Valid @PathVariable("id") Long id, @PathVariable("u public LinkedHashSet viewRating(@RequestParam(defaultValue = "10") Long count) { return filmInterface.viewRating(count); } - - /** - * преобразует FilmRequest в объект Buffer - * - * @param filmRequest объект FilmRequest - * @return объект Buffer - */ - private Buffer parseFilmRequestToBuffer(FilmResponse filmRequest) { - List genreIds = filmRequest.getGenres().stream() - .map(Genre::getId) // Получаем id каждого жанра - .map(String::valueOf) // Преобразуем Long в String - .toList(); // Собираем в List - - return Buffer.of( - filmRequest.getId(), - filmRequest.getName(), - filmRequest.getDescription(), - filmRequest.getReleaseDate(), - filmRequest.getDuration(), - genreIds, // Теперь это List - filmRequest.getMpa().getId() - ); - } - -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index f1785c8..ba79066 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -183,6 +183,15 @@ public FilmResponse findById(Long id) { } @Override + public FilmResponse create(Film film) { + return null; + } + + @Override + public FilmResponse update(Film newFilm) { + return null; + } + public FilmResponse create(@Valid Buffer buffer) { log.info(LOG_CREATE_REQUEST); validateBuffer(buffer); @@ -199,7 +208,6 @@ public FilmResponse create(@Valid Buffer buffer) { return FilmResponse.of(filmId, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres); } - @Override public FilmResponse update(@Valid Buffer newFilm) { log.info(LOG_UPDATE_REQUEST); if (newFilm.getId() == null) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java index 9b12145..86f851c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java @@ -12,7 +12,7 @@ public interface FilmStorage { FilmResponse findById(Long id); - FilmResponse create(Buffer film); + FilmResponse create(Film film); - FilmResponse update(Buffer newFilm); + FilmResponse update(Film newFilm); } \ No newline at end of file From 239d5ddf66929fd27299b69becaedc73b049f279 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 18:15:19 +0500 Subject: [PATCH 110/118] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/yandex/practicum/filmorate/storage/film/FilmStorage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java index 86f851c..9000af3 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java @@ -1,6 +1,5 @@ package ru.yandex.practicum.filmorate.storage.film; -import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmResponse; From f04cfc26dbb2818e8b4cc8048de892dd33a4c0d7 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 18:18:05 +0500 Subject: [PATCH 111/118] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D1=82=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 60 +++++++++++++++++-- .../filmorate/storage/film/FilmDbStorage.java | 10 +--- .../filmorate/storage/film/FilmStorage.java | 5 +- 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 67aaf36..b0a6080 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,22 +1,28 @@ package ru.yandex.practicum.filmorate.controller; +import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmResponse; import ru.yandex.practicum.filmorate.service.FilmInterface; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.util.LinkedHashSet; -import java.util.List; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.*; @RestController @RequestMapping("/films") public class FilmController { + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static final String DEFAULT_GENRE = "нет жанра"; + private final FilmStorage filmStorage; private final UserStorage userStorage; private final FilmInterface filmInterface; @@ -44,13 +50,15 @@ public FilmResponse findById(@PathVariable("id") Long id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmResponse create(@Valid @RequestBody Film film) { - return filmStorage.create(film); + public FilmResponse create(@Valid @RequestBody ObjectNode objectNode) { + Buffer buffer = parseObjectNodeToBuffer(objectNode); + return filmStorage.create(buffer); } @PutMapping - public FilmResponse update(@Valid @RequestBody Film film) { - return filmStorage.update(film); + public FilmResponse update(@Valid @RequestBody ObjectNode objectNode) { + Buffer buffer = parseObjectNodeToBuffer(objectNode); + return filmStorage.update(buffer); } @PutMapping("/{id}/like/{userId}") @@ -67,4 +75,44 @@ public FilmResponse delLike(@Valid @PathVariable("id") Long id, @PathVariable("u public LinkedHashSet viewRating(@RequestParam(defaultValue = "10") Long count) { return filmInterface.viewRating(count); } + + /** + * преобразует json объект в объект Buffer + * + * @param objectNode json объект + * @return объект Buffer + */ + private Buffer parseObjectNodeToBuffer(ObjectNode objectNode) { + Long id = objectNode.has("id") ? objectNode.get("id").asLong() : 0L; + String name = objectNode.get("name").asText(); + String description = objectNode.get("description").asText(); + String releaseDate = objectNode.get("releaseDate").asText(); + Integer duration = objectNode.get("duration").asInt(); + List mpa = objectNode.get("mpa").findValuesAsText("id"); + List genres = extractGenresFromObjectNode(objectNode); + + return Buffer.of( + id, + name, + description, + LocalDate.parse(releaseDate, DATE_FORMATTER), + duration, + genres, + Long.valueOf(mpa.get(0)) + ); + } + + /** + * извлекает список жанров из json объекта + * + * @param objectNode json объект + * @return список жанров + */ + private List extractGenresFromObjectNode(ObjectNode objectNode) { + try { + return objectNode.get("genres").findValuesAsText("id"); + } catch (NullPointerException e) { + return List.of(DEFAULT_GENRE); + } + } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java index ba79066..f1785c8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorage.java @@ -183,15 +183,6 @@ public FilmResponse findById(Long id) { } @Override - public FilmResponse create(Film film) { - return null; - } - - @Override - public FilmResponse update(Film newFilm) { - return null; - } - public FilmResponse create(@Valid Buffer buffer) { log.info(LOG_CREATE_REQUEST); validateBuffer(buffer); @@ -208,6 +199,7 @@ public FilmResponse create(@Valid Buffer buffer) { return FilmResponse.of(filmId, buffer.getName(), buffer.getDescription(), buffer.getReleaseDate(), buffer.getDuration(), new HashSet<>(), Mpa.of(buffer.getMpa(), rating.get(buffer.getMpa())), genres); } + @Override public FilmResponse update(@Valid Buffer newFilm) { log.info(LOG_UPDATE_REQUEST); if (newFilm.getId() == null) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java index 9000af3..9b12145 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/film/FilmStorage.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.storage.film; +import ru.yandex.practicum.filmorate.model.Buffer; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.FilmResponse; @@ -11,7 +12,7 @@ public interface FilmStorage { FilmResponse findById(Long id); - FilmResponse create(Film film); + FilmResponse create(Buffer film); - FilmResponse update(Film newFilm); + FilmResponse update(Buffer newFilm); } \ No newline at end of file From 60500ad7f3113e7d8803a99884c3447252ba9ebd Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 18:29:04 +0500 Subject: [PATCH 112/118] sss --- .../filmorate/service/FilmService.java | 79 +++++++++++++++---- 1 file changed, 65 insertions(+), 14 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 083fc31..e04c115 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -2,15 +2,19 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.FilmResponse; +import ru.yandex.practicum.filmorate.model.Genre; +import ru.yandex.practicum.filmorate.model.Mpa; import ru.yandex.practicum.filmorate.storage.film.FilmDbStorage; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; +import java.time.LocalDate; import java.util.*; @Service @@ -75,22 +79,69 @@ public FilmResponse delLike(Long idUser, Long idFilm) { public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); - LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); - LinkedHashSet films = new LinkedHashSet<>(); - if (likedUsers == null) { + + if (count == null || count <= 0) { + log.error("Некорректное значение параметра count: {}", count); + throw new IllegalArgumentException("Параметр count должен быть положительным числом."); + } + + String query = """ + SELECT f.id AS film_id, + f.name AS film_name, + f.description AS film_description, + f.release_date AS film_release_date, + f.duration AS film_duration, + f.mpa_id AS film_mpa_id, + m.name AS mpa_name, + g.id AS genre_id, + g.name AS genre_name, + COUNT(l.user_id) OVER (PARTITION BY f.id) AS likes_count + FROM films f + LEFT JOIN film_genres fg ON f.id = fg.film_id + LEFT JOIN genres g ON fg.genre_id = g.id + LEFT JOIN likes l ON f.id = l.film_id + LEFT JOIN mpa m ON f.mpa_id = m.id + ORDER BY likes_count DESC, f.id ASC + LIMIT ? + """; + + try { + Map filmMap = new LinkedHashMap<>(); + jdbcTemplate.query(query, (rs, rowNum) -> { + Long filmId = rs.getLong("film_id"); + String name = rs.getString("film_name"); + String description = rs.getString("film_description"); + LocalDate releaseDate = rs.getDate("film_release_date").toLocalDate(); + Integer duration = rs.getInt("film_duration"); + Long mpaId = rs.getLong("film_mpa_id"); + String mpaName = rs.getString("mpa_name"); + Long genreId = rs.getObject("genre_id", Long.class); + String genreName = rs.getString("genre_name"); + + // Создаем объект Mpa + Mpa mpa = Mpa.of(mpaId, mpaName); + + // Создаем или обновляем фильм + FilmResponse film = filmMap.get(filmId); + if (film == null) { + LinkedHashSet genres = new LinkedHashSet<>(); + if (genreId != null && genreName != null) { + genres.add(Genre.of(genreId, genreName)); + } + film = FilmResponse.of(filmId, name, description, releaseDate, duration, null, mpa, genres); + filmMap.put(filmId, film); + } else { + if (genreId != null && genreName != null) { + film.getGenres().add(Genre.of(genreId, genreName)); + } + } + return null; + }, count); + + return new LinkedHashSet<>(filmMap.values()); + } catch (EmptyResultDataAccessException e) { log.error("Список фильмов с рейтингом пуст."); throw new NotFoundException("Список фильмов с рейтингом пуст."); - } else { - LinkedHashSet genres = new LinkedHashSet<>(); - for (Long l : likedUsers.keySet()) { - Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); - if (!filmGenre.isEmpty()) { - for (Long g : filmGenre.get(filmStorage.findById(l).getId())) - genres.add(g); - } - films.add(FilmResponse.of(filmStorage.findById(l).getId(), filmStorage.findById(l).getName(), filmStorage.findById(l).getDescription(), filmStorage.findById(l).getReleaseDate(), filmStorage.findById(l).getDuration(), new HashSet<>(), filmStorage.findById(l).getMpa(), genres)); - } } - return films; } } \ No newline at end of file From 2c6864af5b6955ca94484adeac70c65506822cdc Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 18:34:54 +0500 Subject: [PATCH 113/118] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/FilmService.java | 79 ++++--------------- 1 file changed, 14 insertions(+), 65 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index e04c115..083fc31 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -2,19 +2,15 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.FilmResponse; -import ru.yandex.practicum.filmorate.model.Genre; -import ru.yandex.practicum.filmorate.model.Mpa; import ru.yandex.practicum.filmorate.storage.film.FilmDbStorage; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.time.LocalDate; import java.util.*; @Service @@ -79,69 +75,22 @@ public FilmResponse delLike(Long idUser, Long idFilm) { public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); - - if (count == null || count <= 0) { - log.error("Некорректное значение параметра count: {}", count); - throw new IllegalArgumentException("Параметр count должен быть положительным числом."); - } - - String query = """ - SELECT f.id AS film_id, - f.name AS film_name, - f.description AS film_description, - f.release_date AS film_release_date, - f.duration AS film_duration, - f.mpa_id AS film_mpa_id, - m.name AS mpa_name, - g.id AS genre_id, - g.name AS genre_name, - COUNT(l.user_id) OVER (PARTITION BY f.id) AS likes_count - FROM films f - LEFT JOIN film_genres fg ON f.id = fg.film_id - LEFT JOIN genres g ON fg.genre_id = g.id - LEFT JOIN likes l ON f.id = l.film_id - LEFT JOIN mpa m ON f.mpa_id = m.id - ORDER BY likes_count DESC, f.id ASC - LIMIT ? - """; - - try { - Map filmMap = new LinkedHashMap<>(); - jdbcTemplate.query(query, (rs, rowNum) -> { - Long filmId = rs.getLong("film_id"); - String name = rs.getString("film_name"); - String description = rs.getString("film_description"); - LocalDate releaseDate = rs.getDate("film_release_date").toLocalDate(); - Integer duration = rs.getInt("film_duration"); - Long mpaId = rs.getLong("film_mpa_id"); - String mpaName = rs.getString("mpa_name"); - Long genreId = rs.getObject("genre_id", Long.class); - String genreName = rs.getString("genre_name"); - - // Создаем объект Mpa - Mpa mpa = Mpa.of(mpaId, mpaName); - - // Создаем или обновляем фильм - FilmResponse film = filmMap.get(filmId); - if (film == null) { - LinkedHashSet genres = new LinkedHashSet<>(); - if (genreId != null && genreName != null) { - genres.add(Genre.of(genreId, genreName)); - } - film = FilmResponse.of(filmId, name, description, releaseDate, duration, null, mpa, genres); - filmMap.put(filmId, film); - } else { - if (genreId != null && genreName != null) { - film.getGenres().add(Genre.of(genreId, genreName)); - } - } - return null; - }, count); - - return new LinkedHashSet<>(filmMap.values()); - } catch (EmptyResultDataAccessException e) { + LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); + LinkedHashSet films = new LinkedHashSet<>(); + if (likedUsers == null) { log.error("Список фильмов с рейтингом пуст."); throw new NotFoundException("Список фильмов с рейтингом пуст."); + } else { + LinkedHashSet genres = new LinkedHashSet<>(); + for (Long l : likedUsers.keySet()) { + Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); + if (!filmGenre.isEmpty()) { + for (Long g : filmGenre.get(filmStorage.findById(l).getId())) + genres.add(g); + } + films.add(FilmResponse.of(filmStorage.findById(l).getId(), filmStorage.findById(l).getName(), filmStorage.findById(l).getDescription(), filmStorage.findById(l).getReleaseDate(), filmStorage.findById(l).getDuration(), new HashSet<>(), filmStorage.findById(l).getMpa(), genres)); + } } + return films; } } \ No newline at end of file From 0a9c5c1c9530337e54f849e07b4c5ea4ec87b2d0 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 20:05:33 +0500 Subject: [PATCH 114/118] =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/service/FilmService.java | 70 ++++++++++++++++--- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 083fc31..bf454f8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -7,6 +7,7 @@ import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.FilmResponse; +import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.storage.film.FilmDbStorage; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; @@ -74,23 +75,72 @@ public FilmResponse delLike(Long idUser, Long idFilm) { } public LinkedHashSet viewRating(Long count) { - log.info("Обработка Get-запроса..."); - LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); + log.info("Обработка Get-запроса для получения топ {} фильмов...", count); + + if (count == null || count <= 0) { + log.error("Параметр count должен быть положительным числом"); + throw new ConditionsNotMetException("Количество фильмов должно быть положительным числом"); + } + + String limitedTopFilmsQuery = "SELECT f.id as name, COUNT(l.userId) as coun " + + "FROM likedUsers as l " + + "LEFT OUTER JOIN film AS f ON l.filmId = f.id " + + "GROUP BY f.name " + + "ORDER BY COUNT(l.userId) DESC " + + "LIMIT ?"; + + LinkedHashMap likedUsers = jdbcTemplate.query( + limitedTopFilmsQuery, + new TopLikedUsersExtractor(), + count + ); + LinkedHashSet films = new LinkedHashSet<>(); - if (likedUsers == null) { + if (likedUsers == null || likedUsers.isEmpty()) { log.error("Список фильмов с рейтингом пуст."); throw new NotFoundException("Список фильмов с рейтингом пуст."); } else { - LinkedHashSet genres = new LinkedHashSet<>(); - for (Long l : likedUsers.keySet()) { - Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); - if (!filmGenre.isEmpty()) { - for (Long g : filmGenre.get(filmStorage.findById(l).getId())) - genres.add(g); + for (Long filmId : likedUsers.keySet()) { + FilmResponse film = filmStorage.findById(filmId); + LinkedHashSet genres = new LinkedHashSet<>(); + + Map> filmGenre = jdbcTemplate.query( + selectFilmGenresQuery, + new FilmDbStorage.FilmGenreExtractor(), + filmId + ); + + if (!filmGenre.isEmpty() && filmGenre.get(filmId) != null) { + for (Long genreId : filmGenre.get(filmId)) { + genres.add(getGenreById(genreId)); + } + } + + films.add(FilmResponse.of( + film.getId(), + film.getName(), + film.getDescription(), + film.getReleaseDate(), + film.getDuration(), + new HashSet<>(), + film.getMpa(), + genres + )); + + if (films.size() >= count) { + break; } - films.add(FilmResponse.of(filmStorage.findById(l).getId(), filmStorage.findById(l).getName(), filmStorage.findById(l).getDescription(), filmStorage.findById(l).getReleaseDate(), filmStorage.findById(l).getDuration(), new HashSet<>(), filmStorage.findById(l).getMpa(), genres)); } } return films; } + + private Genre getGenreById(Long genreId) { + String genreQuery = "SELECT id, name FROM genres WHERE id = ?"; + return jdbcTemplate.queryForObject( + genreQuery, + (rs, rowNum) -> Genre.of(rs.getLong("id"), rs.getString("name")), + genreId + ); + } } \ No newline at end of file From bb81b4efa565ca10156c5af3bcee579c2f318190 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 20:19:54 +0500 Subject: [PATCH 115/118] dd --- .../filmorate/service/FilmService.java | 70 +++---------------- 1 file changed, 10 insertions(+), 60 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index bf454f8..dd4230e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -7,7 +7,6 @@ import ru.yandex.practicum.filmorate.exception.ConditionsNotMetException; import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.FilmResponse; -import ru.yandex.practicum.filmorate.model.Genre; import ru.yandex.practicum.filmorate.storage.film.FilmDbStorage; import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; @@ -75,72 +74,23 @@ public FilmResponse delLike(Long idUser, Long idFilm) { } public LinkedHashSet viewRating(Long count) { - log.info("Обработка Get-запроса для получения топ {} фильмов...", count); - - if (count == null || count <= 0) { - log.error("Параметр count должен быть положительным числом"); - throw new ConditionsNotMetException("Количество фильмов должно быть положительным числом"); - } - - String limitedTopFilmsQuery = "SELECT f.id as name, COUNT(l.userId) as coun " + - "FROM likedUsers as l " + - "LEFT OUTER JOIN film AS f ON l.filmId = f.id " + - "GROUP BY f.name " + - "ORDER BY COUNT(l.userId) DESC " + - "LIMIT ?"; - - LinkedHashMap likedUsers = jdbcTemplate.query( - limitedTopFilmsQuery, - new TopLikedUsersExtractor(), - count - ); - + log.info("Обработка Get-запроса..."); + LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor(), count); LinkedHashSet films = new LinkedHashSet<>(); - if (likedUsers == null || likedUsers.isEmpty()) { + if (likedUsers == null) { log.error("Список фильмов с рейтингом пуст."); throw new NotFoundException("Список фильмов с рейтингом пуст."); } else { - for (Long filmId : likedUsers.keySet()) { - FilmResponse film = filmStorage.findById(filmId); - LinkedHashSet genres = new LinkedHashSet<>(); - - Map> filmGenre = jdbcTemplate.query( - selectFilmGenresQuery, - new FilmDbStorage.FilmGenreExtractor(), - filmId - ); - - if (!filmGenre.isEmpty() && filmGenre.get(filmId) != null) { - for (Long genreId : filmGenre.get(filmId)) { - genres.add(getGenreById(genreId)); - } - } - - films.add(FilmResponse.of( - film.getId(), - film.getName(), - film.getDescription(), - film.getReleaseDate(), - film.getDuration(), - new HashSet<>(), - film.getMpa(), - genres - )); - - if (films.size() >= count) { - break; + LinkedHashSet genres = new LinkedHashSet<>(); + for (Long l : likedUsers.keySet()) { + Map> filmGenre = jdbcTemplate.query(selectFilmGenresQuery, new FilmDbStorage.FilmGenreExtractor(), filmStorage.findById(l).getId()); + if (!filmGenre.isEmpty()) { + for (Long g : filmGenre.get(filmStorage.findById(l).getId())) + genres.add(g); } + films.add(FilmResponse.of(filmStorage.findById(l).getId(), filmStorage.findById(l).getName(), filmStorage.findById(l).getDescription(), filmStorage.findById(l).getReleaseDate(), filmStorage.findById(l).getDuration(), new HashSet<>(), filmStorage.findById(l).getMpa(), genres)); } } return films; } - - private Genre getGenreById(Long genreId) { - String genreQuery = "SELECT id, name FROM genres WHERE id = ?"; - return jdbcTemplate.queryForObject( - genreQuery, - (rs, rowNum) -> Genre.of(rs.getLong("id"), rs.getString("name")), - genreId - ); - } } \ No newline at end of file From a44d1df6d1bec244d9d9b9afcd592a2f0f6de473 Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 20:25:16 +0500 Subject: [PATCH 116/118] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ru/yandex/practicum/filmorate/service/FilmService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index dd4230e..083fc31 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -75,7 +75,7 @@ public FilmResponse delLike(Long idUser, Long idFilm) { public LinkedHashSet viewRating(Long count) { log.info("Обработка Get-запроса..."); - LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor(), count); + LinkedHashMap likedUsers = jdbcTemplate.query(selectTopFilmsQuery, new TopLikedUsersExtractor()); LinkedHashSet films = new LinkedHashSet<>(); if (likedUsers == null) { log.error("Список фильмов с рейтингом пуст."); From 3089811dafba062694b049b63b7fca3f2bb468ef Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 20:34:55 +0500 Subject: [PATCH 117/118] =?UTF-8?q?=D0=BE=D0=BF=D1=8F=D1=82=D1=8C=20=D0=BA?= =?UTF-8?q?=D0=BB=D0=B0=D1=81=D1=81=20=D0=BF=D0=BE=20=D0=BF=D0=B0=D1=80?= =?UTF-8?q?=D1=81=D0=B8=D0=BD=D0=B3=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 59 ++----------------- 1 file changed, 6 insertions(+), 53 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index b0a6080..7885de9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,6 +1,5 @@ package ru.yandex.practicum.filmorate.controller; -import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -12,17 +11,13 @@ import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.LinkedHashSet; +import java.util.List; @RestController @RequestMapping("/films") public class FilmController { - private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - private static final String DEFAULT_GENRE = "нет жанра"; - private final FilmStorage filmStorage; private final UserStorage userStorage; private final FilmInterface filmInterface; @@ -50,24 +45,22 @@ public FilmResponse findById(@PathVariable("id") Long id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmResponse create(@Valid @RequestBody ObjectNode objectNode) { - Buffer buffer = parseObjectNodeToBuffer(objectNode); + public FilmResponse create(@Valid @RequestBody Buffer buffer) { return filmStorage.create(buffer); } @PutMapping - public FilmResponse update(@Valid @RequestBody ObjectNode objectNode) { - Buffer buffer = parseObjectNodeToBuffer(objectNode); + public FilmResponse update(@Valid @RequestBody Buffer buffer) { return filmStorage.update(buffer); } @PutMapping("/{id}/like/{userId}") - public FilmResponse addLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { + public FilmResponse addLike(@PathVariable("id") Long id, @PathVariable("userId") Long userId) { return filmInterface.addLike(userId, id); } @DeleteMapping("/{id}/like/{userId}") - public FilmResponse delLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { + public FilmResponse delLike(@PathVariable("id") Long id, @PathVariable("userId") Long userId) { return filmInterface.delLike(userId, id); } @@ -75,44 +68,4 @@ public FilmResponse delLike(@Valid @PathVariable("id") Long id, @PathVariable("u public LinkedHashSet viewRating(@RequestParam(defaultValue = "10") Long count) { return filmInterface.viewRating(count); } - - /** - * преобразует json объект в объект Buffer - * - * @param objectNode json объект - * @return объект Buffer - */ - private Buffer parseObjectNodeToBuffer(ObjectNode objectNode) { - Long id = objectNode.has("id") ? objectNode.get("id").asLong() : 0L; - String name = objectNode.get("name").asText(); - String description = objectNode.get("description").asText(); - String releaseDate = objectNode.get("releaseDate").asText(); - Integer duration = objectNode.get("duration").asInt(); - List mpa = objectNode.get("mpa").findValuesAsText("id"); - List genres = extractGenresFromObjectNode(objectNode); - - return Buffer.of( - id, - name, - description, - LocalDate.parse(releaseDate, DATE_FORMATTER), - duration, - genres, - Long.valueOf(mpa.get(0)) - ); - } - - /** - * извлекает список жанров из json объекта - * - * @param objectNode json объект - * @return список жанров - */ - private List extractGenresFromObjectNode(ObjectNode objectNode) { - try { - return objectNode.get("genres").findValuesAsText("id"); - } catch (NullPointerException e) { - return List.of(DEFAULT_GENRE); - } - } } \ No newline at end of file From 265b785f200fd06abd83cf1d40dea99a259d115d Mon Sep 17 00:00:00 2001 From: Valerii_Butko Date: Mon, 3 Mar 2025 20:39:01 +0500 Subject: [PATCH 118/118] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filmorate/controller/FilmController.java | 59 +++++++++++++++++-- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 7885de9..b0a6080 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.controller; +import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -11,13 +12,17 @@ import ru.yandex.practicum.filmorate.storage.film.FilmStorage; import ru.yandex.practicum.filmorate.storage.user.UserStorage; -import java.util.LinkedHashSet; -import java.util.List; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.*; @RestController @RequestMapping("/films") public class FilmController { + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static final String DEFAULT_GENRE = "нет жанра"; + private final FilmStorage filmStorage; private final UserStorage userStorage; private final FilmInterface filmInterface; @@ -45,22 +50,24 @@ public FilmResponse findById(@PathVariable("id") Long id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FilmResponse create(@Valid @RequestBody Buffer buffer) { + public FilmResponse create(@Valid @RequestBody ObjectNode objectNode) { + Buffer buffer = parseObjectNodeToBuffer(objectNode); return filmStorage.create(buffer); } @PutMapping - public FilmResponse update(@Valid @RequestBody Buffer buffer) { + public FilmResponse update(@Valid @RequestBody ObjectNode objectNode) { + Buffer buffer = parseObjectNodeToBuffer(objectNode); return filmStorage.update(buffer); } @PutMapping("/{id}/like/{userId}") - public FilmResponse addLike(@PathVariable("id") Long id, @PathVariable("userId") Long userId) { + public FilmResponse addLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { return filmInterface.addLike(userId, id); } @DeleteMapping("/{id}/like/{userId}") - public FilmResponse delLike(@PathVariable("id") Long id, @PathVariable("userId") Long userId) { + public FilmResponse delLike(@Valid @PathVariable("id") Long id, @PathVariable("userId") Long userId) { return filmInterface.delLike(userId, id); } @@ -68,4 +75,44 @@ public FilmResponse delLike(@PathVariable("id") Long id, @PathVariable("userId") public LinkedHashSet viewRating(@RequestParam(defaultValue = "10") Long count) { return filmInterface.viewRating(count); } + + /** + * преобразует json объект в объект Buffer + * + * @param objectNode json объект + * @return объект Buffer + */ + private Buffer parseObjectNodeToBuffer(ObjectNode objectNode) { + Long id = objectNode.has("id") ? objectNode.get("id").asLong() : 0L; + String name = objectNode.get("name").asText(); + String description = objectNode.get("description").asText(); + String releaseDate = objectNode.get("releaseDate").asText(); + Integer duration = objectNode.get("duration").asInt(); + List mpa = objectNode.get("mpa").findValuesAsText("id"); + List genres = extractGenresFromObjectNode(objectNode); + + return Buffer.of( + id, + name, + description, + LocalDate.parse(releaseDate, DATE_FORMATTER), + duration, + genres, + Long.valueOf(mpa.get(0)) + ); + } + + /** + * извлекает список жанров из json объекта + * + * @param objectNode json объект + * @return список жанров + */ + private List extractGenresFromObjectNode(ObjectNode objectNode) { + try { + return objectNode.get("genres").findValuesAsText("id"); + } catch (NullPointerException e) { + return List.of(DEFAULT_GENRE); + } + } } \ No newline at end of file