Repository navigation
Add film director #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| package ru.yandex.practicum.filmorate.controller; | ||
|
|
||
| import jakarta.validation.Valid; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.web.bind.annotation.*; | ||
| import ru.yandex.practicum.filmorate.model.Director; | ||
| import ru.yandex.practicum.filmorate.service.DirectorService; | ||
| import java.util.List; | ||
|
|
||
| @Slf4j | ||
| @RestController | ||
| @RequestMapping("/directors") | ||
| public class DirectorController { | ||
|
|
||
| private final DirectorService directorService; | ||
|
|
||
| @Autowired | ||
| public DirectorController(DirectorService directorService) { | ||
| this.directorService = directorService; | ||
| } | ||
|
|
||
| @GetMapping | ||
| public List<Director> getDirectors() { | ||
| log.info("GET /directors"); | ||
| return directorService.getAllDirectors(); | ||
| } | ||
|
|
||
| @GetMapping("/{id}") | ||
| public Director getDirectorById(@PathVariable Long id) { | ||
| log.info("GET /directors/{}", id); | ||
| return directorService.getDirectorById(id); | ||
| } | ||
|
|
||
| @PostMapping | ||
| public Director createDirector(@Valid @RequestBody Director director) { | ||
| log.info("POST /directors, body:{}", director); | ||
| return directorService.addDirector(director); | ||
| } | ||
|
|
||
| @PutMapping | ||
| public Director updateDirector(@Valid @RequestBody Director director) { | ||
| log.info("PUT /directors, body:{}", director); | ||
| return directorService.updateDirector(director); | ||
| } | ||
|
|
||
| @DeleteMapping("/{id}") | ||
| public void deleteDirector(@PathVariable Long id) { | ||
| log.info("DELETE /directors/{}", id); | ||
| directorService.deleteDirector(id); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package ru.yandex.practicum.filmorate.model; | ||
|
|
||
| import jakarta.validation.constraints.NotBlank; | ||
| import lombok.Data; | ||
|
|
||
| @Data | ||
| public class Director { | ||
| private Long id; | ||
|
|
||
| @NotBlank(message = "Имя режиссера не может быть пустым") | ||
| private String name; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package ru.yandex.practicum.filmorate.service; | ||
|
|
||
| import org.springframework.beans.factory.annotation.Qualifier; | ||
| import org.springframework.stereotype.Service; | ||
| import ru.yandex.practicum.filmorate.exception.NotFoundException; | ||
| import ru.yandex.practicum.filmorate.model.Director; | ||
| import ru.yandex.practicum.filmorate.storage.director.DirectorStorage; | ||
|
|
||
| @Service | ||
| public class DirectorService { | ||
|
|
||
| private final DirectorStorage directorStorage; | ||
|
|
||
| public DirectorService(@Qualifier("directorDbStorage") DirectorStorage directorStorage) { | ||
| this.directorStorage = directorStorage; | ||
| } | ||
|
|
||
| public Director addDirector(Director director) { | ||
| return directorStorage.addDirector(director); | ||
| } | ||
|
|
||
| public Director updateDirector(Director director) { | ||
| return directorStorage.updateDirector(director); | ||
| } | ||
|
|
||
| public void deleteDirector(long id) { | ||
| directorStorage.removeDirector(id); | ||
| } | ||
|
|
||
| public Director getDirectorById(long id) { | ||
| return directorStorage.findDirectorById(id) | ||
| .orElseThrow(() -> new NotFoundException("Режиссер с id " + id + " не найден")); | ||
| } | ||
|
|
||
| public java.util.List<Director> getAllDirectors() { | ||
| return directorStorage.findAllDirectors(); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |
| import org.springframework.stereotype.Service; | ||
| import ru.yandex.practicum.filmorate.exception.NotFoundException; | ||
| import ru.yandex.practicum.filmorate.exception.ValidationException; | ||
| import ru.yandex.practicum.filmorate.model.Director; | ||
| import ru.yandex.practicum.filmorate.model.Film; | ||
| import ru.yandex.practicum.filmorate.model.Genre; | ||
| import ru.yandex.practicum.filmorate.storage.film.FilmStorage; | ||
|
|
@@ -30,16 +31,19 @@ public class FilmService { | |
| // Нужны для проверки рейтинга и жанра из запроса | ||
| private final MpaService mpaService; | ||
| private final GenreService genreService; | ||
| private final DirectorService directorService; | ||
|
|
||
| @Autowired | ||
| public FilmService(@Qualifier("filmDbStorage") FilmStorage filmStorage, | ||
| @Qualifier("userDbStorage") UserStorage userStorage, | ||
| MpaService mpaService, | ||
| GenreService genreService) { | ||
| GenreService genreService, | ||
| DirectorService directorService) { | ||
| this.filmStorage = filmStorage; | ||
| this.userStorage = userStorage; | ||
| this.mpaService = mpaService; | ||
| this.genreService = genreService; | ||
| this.directorService = directorService; | ||
| } | ||
|
|
||
| // Получение фильма по id с проверкой существования | ||
|
|
@@ -134,16 +138,35 @@ private void validateMpaAndGenres(Film film) { | |
| } | ||
| } | ||
|
|
||
| private void validateDirectors(Film film) { | ||
|
|
||
| if (film.getDirectors() == null || film.getDirectors().isEmpty()) { | ||
| return; | ||
| } | ||
|
|
||
| Set<Long> knownIds = new HashSet<>(); | ||
| for (Director director : directorService.getAllDirectors()) { | ||
| knownIds.add(director.getId()); | ||
| } | ||
| for (Director director : film.getDirectors()) { | ||
| if (!knownIds.contains(director.getId())) { | ||
| throw new NotFoundException("Режиссёр с id=" + director.getId() + " не найден"); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public Film add(Film film) { | ||
| validateReleaseDate(film); | ||
| validateMpaAndGenres(film); | ||
| validateDirectors(film); | ||
| return filmStorage.add(film); | ||
| } | ||
|
|
||
| public Film update(Film film) { | ||
| getFilmOrThrow(film.getId()); // проверка существования — иначе 404 | ||
| validateReleaseDate(film); | ||
| validateMpaAndGenres(film); | ||
| validateDirectors(film); | ||
| return filmStorage.update(film); | ||
| } | ||
|
|
||
|
|
@@ -160,4 +183,9 @@ public Collection<Film> findAll() { | |
| public Film findById(long id) { | ||
| return getFilmOrThrow(id); | ||
| } | ||
|
|
||
| public Collection<Film> findByDirectorSorted(long directorId, String sortBy) { | ||
| directorService.getDirectorById(directorId); // проверка существования режиссёра — иначе 404 | ||
| return filmStorage.findFilmByDirector(directorId, sortBy); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Для несуществующего режиссёра сейчас 200 и пустой список, а везде в проекте на несуществующий id - 404: например, в getCommon сначала проверяются пользователи. |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| package ru.yandex.practicum.filmorate.storage.director; | ||
|
|
||
| import java.util.Optional; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.jdbc.core.JdbcTemplate; | ||
| import org.springframework.jdbc.support.GeneratedKeyHolder; | ||
| import org.springframework.jdbc.support.KeyHolder; | ||
| import org.springframework.stereotype.Repository; | ||
| import ru.yandex.practicum.filmorate.exception.NotFoundException; | ||
| import ru.yandex.practicum.filmorate.model.Director; | ||
| import ru.yandex.practicum.filmorate.storage.mapper.DirectorRowMapper; | ||
| import java.util.List; | ||
|
|
||
| @Repository | ||
| public class DirectorDbStorage implements DirectorStorage { | ||
|
|
||
| private final JdbcTemplate jdbcTemplate; | ||
| private final DirectorRowMapper directorRowMapper; | ||
|
|
||
| private static final String INSERT_QUERY = "INSERT INTO directors (name) VALUES (?)"; | ||
| private static final String UPDATE_QUERY = "UPDATE directors SET name = ? WHERE id = ?"; | ||
| private static final String DELETE_QUERY = "DELETE FROM directors WHERE id = ?"; | ||
| private static final String SELECT_BY_ID_QUERY = "SELECT * FROM directors WHERE id = ?"; | ||
| private static final String SELECT_ALL_QUERY = "SELECT * FROM directors ORDER BY id"; | ||
|
|
||
| @Autowired | ||
| public DirectorDbStorage(JdbcTemplate jdbcTemplate, DirectorRowMapper directorRowMapper) { | ||
| this.jdbcTemplate = jdbcTemplate; | ||
| this.directorRowMapper = directorRowMapper; | ||
| } | ||
|
|
||
| @Override | ||
| public Director addDirector(Director director) { | ||
| KeyHolder keyHolder = new GeneratedKeyHolder(); | ||
| jdbcTemplate.update(connection -> { | ||
| var ps = connection.prepareStatement(INSERT_QUERY, new String[]{"id"}); | ||
| ps.setString(1, director.getName()); | ||
| return ps; | ||
| }, keyHolder); | ||
| director.setId(keyHolder.getKey().longValue()); | ||
| return director; | ||
| } | ||
|
|
||
| @Override | ||
| public Director updateDirector(Director director) { | ||
| int updatedRows = jdbcTemplate.update( | ||
| UPDATE_QUERY, | ||
| director.getName(), | ||
| director.getId() | ||
| ); | ||
|
|
||
| if (updatedRows == 0) { | ||
| throw new NotFoundException( | ||
| "Режиссёр с id=" + director.getId() + " не найден" | ||
| ); | ||
| } | ||
| return director; | ||
| } | ||
|
|
||
| @Override | ||
| public void removeDirector(long id) { | ||
| Director director = findDirectorById(id) | ||
| .orElseThrow(() -> new NotFoundException("Режиссёр с id " + id + " не найден")); | ||
| jdbcTemplate.update(DELETE_QUERY, id); | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<Director> findDirectorById(long id) { | ||
| Optional<Director> director = jdbcTemplate.query(SELECT_BY_ID_QUERY, directorRowMapper, id).stream().findFirst(); | ||
| return director; | ||
| } | ||
|
|
||
| @Override | ||
| public List<Director> findAllDirectors() { | ||
| List<Director> directors = jdbcTemplate.query(SELECT_ALL_QUERY, directorRowMapper); | ||
| return directors; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package ru.yandex.practicum.filmorate.storage.director; | ||
|
|
||
| import ru.yandex.practicum.filmorate.model.Director; | ||
| import java.util.List; | ||
| import java.util.Optional; | ||
|
|
||
| public interface DirectorStorage { | ||
|
|
||
| Director addDirector(Director director); | ||
|
|
||
| Director updateDirector(Director director); | ||
|
|
||
| void removeDirector(long id); | ||
|
|
||
| Optional<Director> findDirectorById(long id); | ||
|
|
||
| List<Director> findAllDirectors(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Сейчас режиссёр с пустым именем сохраняется, а без имени падает с 500 из базы.
Нужна валидация имени - как у name в Film, - и @Valid в POST и PUT контроллера, тогда будет 400.
Это проверяет общий набор тестов Практикума на финальном PR develop -> main ("Create director Fail name").