Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# java-filmorate
Учебный проект.
Созданиие прилощений на основе шаблона "Spring"
Созданиие приложений на основе шаблона "Spring"<br>

## Спринт 10
Добавляем контроллеры фильмов и пользователей.<br>

## Спринт 11
Добавляем работу с "друзьями" и "лайками"
18 changes: 18 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
Expand All @@ -27,11 +32,24 @@
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<dependency>
<groupId>org.zalando</groupId>
<artifactId>logbook-spring-boot-starter</artifactId>
<version>3.7.2</version>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,18 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* Главный класс приложения рейтинга фильмов.
*/
@SpringBootApplication
public class FilmorateApplication {
public static void main(String[] args) {

/**
* Запуск приложения.
*
* @param args - параметры запуска.
*/
public static void main(final String[] args) {
SpringApplication.run(FilmorateApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package ru.yandex.practicum.filmorate.controller;

import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import ru.yandex.practicum.filmorate.exception.NotFoundException;
import ru.yandex.practicum.filmorate.exception.ValidationException;
import ru.yandex.practicum.filmorate.model.ErrorMessage;
import ru.yandex.practicum.filmorate.model.ValidationErrorResponse;
import ru.yandex.practicum.filmorate.model.Violation;

import java.util.List;
import java.util.stream.Collectors;

/**
* Класс обработки исключений при обработке поступивших http запросов
*/
@Slf4j
@RestControllerAdvice
public class ErrorHandler {

/**
* Обработка исключения ConstraintViolationException - при проверке ограничений объекта
*
* @param e - исключение
* @return - список нарушений для отображения в теле ответа
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ValidationErrorResponse onConstraintValidationException(ConstraintViolationException e) {
final List<Violation> violations = e.getConstraintViolations().stream()
.map(
violation -> new Violation(
violation.getPropertyPath().toString(),
violation.getMessage()
)
)
.collect(Collectors.toList());

log.info("400 {}.", e.getMessage());
return new ValidationErrorResponse(violations);
}

/**
* Обработка исключения MethodArgumentNotValidException - при проверке аргумента метода
*
* @param e - исключение
* @return - список нарушений для отображения в теле ответа
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ValidationErrorResponse onMethodArgumentNotValidException(
MethodArgumentNotValidException e
) {
final List<Violation> violations = e.getBindingResult().getFieldErrors().stream()
.map(error -> new Violation(error.getField(), error.getDefaultMessage()))
.collect(Collectors.toList());
log.info("400 {}.", e.getMessage());
return new ValidationErrorResponse(violations);
}

/**
* Метод обработки пользовательского исключения ValidationException
*
* @param exception - исключкние проверки данных
* @return - объект для http ответа с сообщением об ошибке
*/
@ExceptionHandler(ValidationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorMessage onValidationException(ValidationException exception) {
log.info("400 {}.", exception.getMessage());
return new ErrorMessage(exception.getMessage());
}

@ExceptionHandler(NotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorMessage notFoundObject(NotFoundException exception) {
log.info("404 {}.", exception.getMessage());
return new ErrorMessage(exception.getMessage());
}

/**
* Обработка исключения HttpMessageNotReadableException при поступлении пустого запроса
*
* @param e - исключкние генерируемое при отсутствии обязательных данных в теле запроса
* @return - объект для http ответа с сообщением об ошибке
*/
@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<ErrorMessage> onHttpMessageNotReadableException(
HttpMessageNotReadableException e) {
log.info("400 {}.", e.getMessage());
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ErrorMessage("В запросе отсутствуют необходимые данные."));
}

/**
* Обработка непредвиденного исключения
*
* @param e - исключение
* @return - сообщение об ошибке
*/
@ExceptionHandler
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorMessage handleException(final Exception e) {
log.warn("Error", e);
return new ErrorMessage(e.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,119 @@
package ru.yandex.practicum.filmorate.controller;

import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import ru.yandex.practicum.filmorate.model.Film;
import ru.yandex.practicum.filmorate.model.Marker;
import ru.yandex.practicum.filmorate.service.FilmService;

import java.util.Collection;
import java.util.Map;

/**
* Класс обработки http запросов к информации о фильмах.
*/
@Slf4j
@RestController
@RequestMapping("/films")
public class FilmController {

private final FilmService service;

@Autowired
public FilmController(FilmService service) {
this.service = service;
}

/**
* Метод поиска всех фильмов
*
* @return - список фильмов
*/
@GetMapping
@ResponseStatus(HttpStatus.OK)
public Collection<Film> findAllFilms() {
log.info("Ищем все фильмы {}.", service.findAllFilms().size());
return service.findAllFilms();
}

/**
* Метод поиска фильма по идентификатору
*
* @param id - идентификатор
* @return - найденный фильм
*/
@GetMapping("/{id}")
public Film findFilm(@PathVariable Integer id) {
log.info("Ищем фильм id={}.", id);
return service.getFilmById(id);
}

@GetMapping("/popular")
public Collection<Film> findPopularFilms(@RequestParam(defaultValue = "10") int count) {
log.info("Ищем популярные {} фильмов.", count);
return service.findPopularFilms(count);
}

/**
* Метод добавления нового фильма.
*
* @param film - объект для добавления
* @return - подтверждение добавленного объекта
*/
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Film addNewFilm(@Validated(Marker.OnBasic.class) @RequestBody Film film) {
log.info("Добавляем новй фильм: {}.", film.toString());
return service.addNewFilm(film);
}

/**
* Метод обновления информации о фильме.
* При вызове метода промзводится проверка аннотаций только для маркера OnUpdate.class.
* Кроме id любой другой параметр может отсутствовать
*
* @param updFilm - объект с обновленной информацией о фильме
* @return - подтверждение обновленного объекта
*/
@PutMapping
@ResponseStatus(HttpStatus.OK)
public Film updateFilm(@Validated(Marker.OnUpdate.class) @RequestBody Film updFilm) {
Integer id = updFilm.getId();
log.info("Обновляем информацию о фильме id={} : {}", id, updFilm.toString());
return service.updateFilm(updFilm);
}

@PutMapping("/{id}/like/{userId}")
@ResponseStatus(HttpStatus.OK)
public Map<String, String> addLike(@PathVariable("id") Integer filmId,
@PathVariable("userId") Integer userId) {
log.debug("Добавляем \"лайк\" фильму {}, от пользователя {}.", filmId, userId);
service.addNewLike(filmId, userId);
return service.getFilmRank(filmId);
}

@DeleteMapping("/{id}/like/{userId}")
@ResponseStatus(HttpStatus.OK)
public Map<String, String> removeLike(@PathVariable("id") Integer filmId,
@PathVariable("userId") Integer userId) {
log.debug("Удаляем \"лайк\" у фильма {}, от пользователя {}.", filmId, userId);
service.removeLike(filmId, userId);
return service.getFilmRank(filmId);
}

/**
* Удаление всех фильмов
*
* @return - сообщение о выполнении
*/
@DeleteMapping
@ResponseStatus(HttpStatus.OK)
public String onDelete() {
log.info("Удаляем все фильмы.");
return service.onDelete();
}

}
Loading
Loading