-
Notifications
You must be signed in to change notification settings - Fork 0
Создал новую ветку controllers-films-users. #1
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
Conversation
Создал пакет model. Реализовал в нем классы: Film и User. Это классы — модели данных приложения. Создал два класса-контроллера. FilmController для фильмов, и UserController для пользователей. Создал UserNotFoundException, ValidationException, GlobalExceptionHandler для валидации. Создал тесты.
afomkina
left a comment
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.
Очень рекоммендую попробовать сделать дополнительное задание, так как сприговая валидация очень популярна в коммерческой разработке и никто не пишет валидацию руками. Она очень сильно сокращает код и избавляет от ошибок "невнимательности". Вот отлчиная статься про аннотации валидации
|
|
||
| final Gson gson = new Gson(); | ||
| final Scanner scanner = new Scanner(System.in); | ||
| System.out.print("Введите JSON => "); |
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.
Код со строк 17-27 нужно удалить
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.
- в FilmorateApplication удалил лишний код.
| } | ||
|
|
||
| @GetMapping | ||
| public Collection<Film> findAll() { |
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.
Лучше возвращать не Collection менее абстрактный интерфейс - List, так мы точно будем знать какой тип коллекции ожидать в ответе
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.
Использовал более конкретный тип List вместо Collection, сделав API более понятным и защитив его от возможных изменений извне.
| } | ||
|
|
||
| @GetMapping | ||
| public Collection<User> findAll() { |
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.
Лучше возвращать не Collection менее абстрактный интерфейс - List, так мы точно будем знать какой тип коллекции ожидать в ответе
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.
Использовал более конкретный тип List вместо Collection, сделав API более понятным и защитив его от возможных изменений извне.
| public class GlobalExceptionHandler { | ||
|
|
||
| @ExceptionHandler(ValidationException.class) | ||
| public ResponseEntity<Map<String, String>> handleValidationException(ValidationException ex) { |
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.
- Вместо
Map<String, String>лучше взвращать объектErrorResponse, в котором будет полеerror, куда нужно будет записывать причину ошибки - Можно сделать код еще лаконичнее, избавившись от обертки
ResponseEntity. Для этого нужно просто добавить аннотацию@ResponseStatus(HttpStatus. BAD_REQUEST)над методом, а в самом методе возвращатьErrorResponse.
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.
Вместо Map<String, String> использовал @ResponseStatus(HttpStatus. BAD_REQUEST), создав ErrorResponse.
| @Data | ||
| public class Film { | ||
|
|
||
| Long id; |
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.
У всех полей класса должен быть модификатор доступа
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.
Указал модификатор доступа для полей класса, для геттеров и сеттеров при аннотации использовал приватный.
|
|
||
| @Data | ||
| public class User { | ||
|
|
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.
У всех полей класса должен быть модификатор доступа
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.
Указал модификатор доступа для полей класса, для геттеров и сеттеров при аннотации использовал приватный.
…ms-users 1) в FilmorateApplication удалил лишний код. 2) в FilmController и UserController использовал более конкретный тип List вместо Collection сделав API более понятным и защищая от возможных изменений извне. 3) в GlobalExceptionHandler вместо Map<String, String> использовал @ResponseStatus(HttpStatus. BAD_REQUEST) создав ErrorResponse. 4) в Film и User указал модификатор доступа для полей класса, для геттеров и сеттеров при аннотации, использовал приватный. 5) Реализовал дополнительное задание используя спринговую валидацию, С помощью аннотаций задав ограничения, которые будут проверяться автоматически: подредактировал Film и User, FilmController и UserController, FilmControllerTests и UserControllerTests. Чтобы Spring не только преобразовал тело запроса в соответствующий класс, но и проверил корректность переданных данных, вместе с аннотацией @RequestBody использовал аннотацию @Valid.
Спасибо) Реализовал дополнительное задание, используя проверку Spring, с помощью аннотаций задав ограничения, которые будут проверяться автоматически: подредактировал классы Film и User, контроллеры FilmController и UserController, тесты FilmControllerTests и UserControllerTests. Чтобы Spring не только преобразовывал тело запроса в соответствующий класс, но и проверял корректность переданных данных, вместе с аннотацией @RequestBody использовал аннотацию @Valid. |
| } | ||
|
|
||
| @PostMapping | ||
| public ResponseEntity<Film> createFilm(@Valid @RequestBody Film film) { |
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.
Здесь лучше тоже использовать @ResponseStatus(HttpStatus.CREATED), чтобы избавиться от дополнительной обертки ResponseEntity и просто возвращать Film
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.
В FilmController в createFilm использовал @ResponseStatus(HttpStatus.CREATED), чтобы избавиться от дополнительной обертки.
| } | ||
|
|
||
| @PutMapping | ||
| public ResponseEntity<Film> updateFilm(@Valid @RequestBody Film film) { |
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.
Нужно использовать @ResponseStatus
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.
В FilmController в updateFilm использовал @ResponseStatus(HttpStatus.ОК).
| public class ErrorResponse { | ||
| private final String error; | ||
|
|
||
| public ErrorResponse(String error) { |
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.
@Data включает в себя аннотацию @RequiredArgsConstructor, поэтому явно его объявлять не нужно
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.
В ErrorResponse убрал явное объявление.
|
|
||
| @ExceptionHandler(UserNotFoundException.class) | ||
| @ResponseStatus(HttpStatus.NOT_FOUND) | ||
| public ErrorResponse handleUserNotFoundException(UserNotFoundException ex) { |
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.
Лучше явно прописать название переменной, как exception. Без сокращений код выглядит более читаемо
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.
В GlobalExceptionHandler убрал сокращения.
| private Long id; | ||
|
|
||
| @NotNull(message = "Название фильма не может быть пустым") | ||
| @NotBlank(message = "Название фильма не может быть пустым") |
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.
На самом деле @NotBlank содержет проверку на null, поэтому добавлять дополнительно @NotNull не нужно
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.
Спасибо) В Film убрал лишние @NotNull.
|
|
||
| @NotNull(message = "Описание фильма не может быть пустым") | ||
| @NotBlank(message = "Описание фильма не может быть пустым") | ||
| private String description; |
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.
Чтобы полностью избавиться от ручной валидации, нужно добавить @Size
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.
В Film description добавил @SiZe на 200 символов.
| private String description; | ||
|
|
||
| @NotNull(message = "Дата выхода не может быть пустой") | ||
| private LocalDate releaseDate; |
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.
Можно реализовать кастомную аннотацию валидации, чтобы полностью отказаться от ручной валидации.
Вот отличная статья, в которой подробно описано, как это можно сделать
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.
Спасибо) Реализовал кастомную аннотацию валидации ReleaseDateValidation для Film.
| private LocalDate releaseDate; | ||
|
|
||
| @NotNull(message = "Длительность не может быть пустой") | ||
| private Integer duration; |
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.
@PositiveOrZero проверяет, что число больше либо равно нулю
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.
В Film duration добавил @PositiveOrZero на длительность фильма.
| user.setId(getNextId()); | ||
|
|
||
| // Проверка на существующий логин | ||
| if (users.values().stream().anyMatch(existingUser -> existingUser.getLogin().equals(user.getLogin()))) { |
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.
Дополнительные оптимизации
Чтобы проверка почты проходила за O(1), нужно завести Set, куда при добавлении нового пользователя мы будем класть его email. Соответственно, перед тем как добавить пользователя, нужно будет посмотреть, есть ли уже в сете подобный email, если есть - то пользователь с таким email уже существует.
Так как поиск и вставка в сете работают в среднем за O(1), то наш алгоритм поиска одинаковых email тоже будет работать в среднем за O(1), а это гораздо быстрее, чем пройтись по всем элементам списка O(n)
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.
В UserController провел дополнительную оптимизацию алгоритма поиска, чтобы проверка почты проходила быстрее, за O(1).
| throw new ValidationException("Ошибка. Попытка добавить логин, который уже существует"); | ||
| } | ||
|
|
||
| if (user.getName() == null || user.getName().isBlank()) { |
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.
Эту проверку можно перенести в конструктор класса User, тогда поле будет автоматически проставляться сразу при создании экземпляра класса
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.
Перенес проверку из UserController в конструктор класса User, создав метод setLogin.
…us.CREATED), чтобы избавиться от дополнительной обертки. 2) В FilmController в updateFilm использовал @ResponseStatus(HttpStatus.ОК). 3) В ErrorResponse убрал явное объявление. 4) В GlobalExceptionHandler убрал сокращения. 5) В Film убрал лишние @NotNull. 6) В Film description добавил @SiZe на 200 символов. 7) Реализовал кастомную аннотацию валидации ReleaseDateValidation для Film. 8) В Film duration добавил @PositiveOrZero на длительность фильма. 9) В UserController провел дополнительную оптимизацию алгоритма поиска, чтобы проверка почты проходила быстрее, за O(1). 10) Перенес проверку init из UserController в конструктор класса User. 11) В User убрал лишние @NotNull.
| throw new UserNotFoundException("Фильм с id = " + film.getId() + " не найден"); | ||
| } | ||
|
|
||
| private void filmValidator(@RequestBody Film film) { |
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.
Этот метод нужно удалить, так как валидация теперь работает с помощью аннотаций
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.
Удалил filmValidator, дублирующий валидацию.
Создал пакет model. Реализовал в нем классы: Film и User. Это классы — модели данных приложения. Создал два класса-контроллера. FilmController для фильмов, и UserController для пользователей. Создал UserNotFoundException, ValidationException, GlobalExceptionHandler для валидации. Создал тесты.