mirror of
https://github.com/OtusTeam/Spring.git
synced 2026-05-30 10:50:42 +00:00
templates updated
This commit is contained in:
@@ -13,12 +13,12 @@
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<spring.version>6.0.12</spring.version>
|
||||
<spring.version>6.0.13</spring.version>
|
||||
<opencsv.version>5.8</opencsv.version>
|
||||
<junit.version>5.10.0</junit.version>
|
||||
<mockito.version>5.4.0</mockito.version>
|
||||
<assertj.version>3.24.2</assertj.version>
|
||||
<lombok.version>1.18.28</lombok.version>
|
||||
<lombok.version>1.18.30</lombok.version>
|
||||
<checkstyle-plugin.version>3.2.2</checkstyle-plugin.version>
|
||||
<checkstyle.version>10.11.0</checkstyle.version>
|
||||
<checkstyle.config.url>
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import lombok.Data;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class AppConfig implements TestFileNameProvider {
|
||||
public class AppProperties implements TestFileNameProvider {
|
||||
|
||||
private String testFileName;
|
||||
|
||||
@@ -16,6 +16,7 @@ public class CsvQuestionDao implements QuestionDao {
|
||||
// Использовать CsvToBean
|
||||
// https://opencsv.sourceforge.net/#collection_based_bean_fields_one_to_many_mappings
|
||||
// Использовать QuestionReadException
|
||||
// Про ресурсы: https://mkyong.com/java/java-read-a-file-from-resources-folder/
|
||||
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<spring.version>6.0.12</spring.version>
|
||||
<spring.version>6.0.13</spring.version>
|
||||
<opencsv.version>5.8</opencsv.version>
|
||||
<junit.version>5.10.0</junit.version>
|
||||
<mockito.version>5.4.0</mockito.version>
|
||||
<assertj.version>3.24.2</assertj.version>
|
||||
<lombok.version>1.18.28</lombok.version>
|
||||
<lombok.version>1.18.30</lombok.version>
|
||||
<checkstyle-plugin.version>3.2.2</checkstyle-plugin.version>
|
||||
<checkstyle.version>10.11.0</checkstyle.version>
|
||||
<checkstyle.config.url>
|
||||
|
||||
+3
-1
@@ -1,8 +1,10 @@
|
||||
package ru.otus.hw.config;
|
||||
|
||||
import lombok.Setter;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
public class AppConfig implements TestConfig, TestFileNameProvider {
|
||||
@Setter
|
||||
public class AppProperties implements TestConfig, TestFileNameProvider {
|
||||
|
||||
// внедрить свойство из application.properties
|
||||
private int rightAnswersCountToPass;
|
||||
@@ -16,6 +16,7 @@ public class CsvQuestionDao implements QuestionDao {
|
||||
// Использовать CsvToBean
|
||||
// https://opencsv.sourceforge.net/#collection_based_bean_fields_one_to_many_mappings
|
||||
// Использовать QuestionReadException
|
||||
// Про ресурсы: https://mkyong.com/java/java-read-a-file-from-resources-folder/
|
||||
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<opencsv.version>5.8</opencsv.version>
|
||||
<lombok.version>1.18.28</lombok.version>
|
||||
<lombok.version>1.18.30</lombok.version>
|
||||
<checkstyle-plugin.version>3.2.2</checkstyle-plugin.version>
|
||||
<checkstyle.version>10.11.0</checkstyle.version>
|
||||
<checkstyle.config.url>
|
||||
|
||||
+1
-2
@@ -9,9 +9,8 @@ import java.util.Map;
|
||||
@Setter
|
||||
// Использовать @ConfigurationProperties.
|
||||
// Сейчас класс соответствует файлу настроек. Чтобы они сюда отобразились нужно только правильно разместить аннотации
|
||||
public class AppConfig implements TestConfig, TestFileNameProvider, LocaleConfig {
|
||||
public class AppProperties implements TestConfig, TestFileNameProvider, LocaleConfig {
|
||||
|
||||
@Getter
|
||||
private int rightAnswersCountToPass;
|
||||
|
||||
@Getter
|
||||
@@ -18,6 +18,7 @@ public class CsvQuestionDao implements QuestionDao {
|
||||
// Использовать CsvToBean
|
||||
// https://opencsv.sourceforge.net/#collection_based_bean_fields_one_to_many_mappings
|
||||
// Использовать QuestionReadException
|
||||
// Про ресурсы: https://mkyong.com/java/java-read-a-file-from-resources-folder/
|
||||
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
package ru.otus.hw.commands;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import ru.otus.hw.converters.BookConverter;
|
||||
import ru.otus.hw.services.BookService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@ShellComponent
|
||||
public class BookCommands {
|
||||
|
||||
private final BookService bookService;
|
||||
|
||||
private final BookConverter bookConverter;
|
||||
|
||||
@ShellMethod(value = "Find all books", key = "ab")
|
||||
public String findAllBooks() {
|
||||
return bookService.findAll().stream()
|
||||
.map(bookConverter::bookToString)
|
||||
.collect(Collectors.joining("," + System.lineSeparator()));
|
||||
}
|
||||
|
||||
@ShellMethod(value = "Find book by id", key = "bbid")
|
||||
public String findBookById(long id) {
|
||||
return bookService.findById(id)
|
||||
.map(bookConverter::bookToString)
|
||||
.orElse("Book with id %d not found".formatted(id));
|
||||
}
|
||||
|
||||
//bins aaaaaaaaaaaaa 1 1,6//bins aaaaaaaaaaaaa 1 1,6
|
||||
@ShellMethod(value = "Insert book", key = "bins")
|
||||
public String insertBook(String title, long authorId, List<Long> genresIds) {
|
||||
var savedBook = bookService.insert(title, authorId, genresIds);
|
||||
return bookConverter.bookToString(savedBook);
|
||||
}
|
||||
|
||||
//bupd 4 dfasdfasdfasd 3 2,5
|
||||
@ShellMethod(value = "Update book", key = "bupd")
|
||||
public String updateBook(long id, String title, long authorId, List<Long> genresIds) {
|
||||
var savedBook = bookService.update(id, title, authorId, genresIds);
|
||||
return bookConverter.bookToString(savedBook);
|
||||
}
|
||||
|
||||
@ShellMethod(value = "Delete book by id", key = "bdel")
|
||||
public void updateBook(long id) {
|
||||
bookService.deleteById(id);
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
package ru.otus.hw.converters;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.otus.hw.models.Book;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class BookConverter {
|
||||
private final AuthorConverter authorConverter;
|
||||
|
||||
private final GenreConverter genreConverter;
|
||||
|
||||
public String bookToString(Book book) {
|
||||
var genresString = book.getGenres().stream()
|
||||
.map(genreConverter::genreToString)
|
||||
.map("{%s}"::formatted)
|
||||
.collect(Collectors.joining(", "));
|
||||
return "Id: %d, title: %s, author: {%s}, genres: [%s]".formatted(
|
||||
book.getId(),
|
||||
book.getTitle(),
|
||||
authorConverter.authorToString(book.getAuthor()),
|
||||
genresString);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package ru.otus.hw.models;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Book {
|
||||
private long id;
|
||||
|
||||
private String title;
|
||||
|
||||
private Author author;
|
||||
|
||||
private List<Genre> genres;
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
package ru.otus.hw.repositories;
|
||||
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import ru.otus.hw.models.Author;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public class AuthorRepositoryJdbc implements AuthorRepository {
|
||||
|
||||
@Override
|
||||
public List<Author> findAll() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Author> findById(long id) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static class AuthorRowMapper implements RowMapper<Author> {
|
||||
|
||||
@Override
|
||||
public Author mapRow(ResultSet rs, int i) throws SQLException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
package ru.otus.hw.repositories;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.support.GeneratedKeyHolder;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import ru.otus.hw.models.Book;
|
||||
import ru.otus.hw.models.Genre;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class BookRepositoryJdbc implements BookRepository {
|
||||
|
||||
private final GenreRepository genreRepository;
|
||||
|
||||
@Override
|
||||
public Optional<Book> findById(long id) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Book> findAll() {
|
||||
var genres = genreRepository.findAll();
|
||||
var relations = getAllGenreRelations();
|
||||
var books = getAllBooksWithoutGenres();
|
||||
mergeBooksInfo(books, genres, relations);
|
||||
return books;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Book save(Book book) {
|
||||
if (book.getId() == 0) {
|
||||
return insert(book);
|
||||
}
|
||||
return update(book);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(long id) {
|
||||
//...
|
||||
}
|
||||
|
||||
private List<Book> getAllBooksWithoutGenres() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
private List<BookGenreRelation> getAllGenreRelations() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
private void mergeBooksInfo(List<Book> booksWithoutGenres, List<Genre> genres,
|
||||
List<BookGenreRelation> relations) {
|
||||
// Добавить книгам (booksWithoutGenres) жанры (genres) в соответствии со связями (relations)
|
||||
}
|
||||
|
||||
private Book insert(Book book) {
|
||||
var keyHolder = new GeneratedKeyHolder();
|
||||
|
||||
//...
|
||||
|
||||
//noinspection DataFlowIssue
|
||||
book.setId(keyHolder.getKeyAs(Long.class));
|
||||
batchInsertGenresRelationsFor(book);
|
||||
return book;
|
||||
}
|
||||
|
||||
private Book update(Book book) {
|
||||
//...
|
||||
|
||||
removeGenresRelationsFor(book);
|
||||
batchInsertGenresRelationsFor(book);
|
||||
|
||||
return book;
|
||||
}
|
||||
|
||||
private void batchInsertGenresRelationsFor(Book book) {
|
||||
// batchUpdate
|
||||
}
|
||||
|
||||
private void removeGenresRelationsFor(Book book) {
|
||||
//...
|
||||
}
|
||||
|
||||
private static class BookRowMapper implements RowMapper<Book> {
|
||||
|
||||
@Override
|
||||
public Book mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ClassCanBeRecord")
|
||||
@RequiredArgsConstructor
|
||||
private static class BookResultSetExtractor implements ResultSetExtractor<List<Book>> {
|
||||
|
||||
@Override
|
||||
public List<Book> extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private record BookGenreRelation(long bookId, long genreId) {
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
package ru.otus.hw.repositories;
|
||||
|
||||
import ru.otus.hw.models.Genre;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface GenreRepository {
|
||||
List<Genre> findAll();
|
||||
|
||||
List<Genre> findAllByIds(List<Long> ids);
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
package ru.otus.hw.repositories;
|
||||
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import ru.otus.hw.models.Genre;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public class GenreRepositoryJdbc implements GenreRepository {
|
||||
|
||||
@Override
|
||||
public List<Genre> findAll() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Genre> findAllByIds(List<Long> ids) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
private static class GnreRowMapper implements RowMapper<Genre> {
|
||||
|
||||
@Override
|
||||
public Genre mapRow(ResultSet rs, int i) throws SQLException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package ru.otus.hw.services;
|
||||
|
||||
import ru.otus.hw.models.Book;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface BookService {
|
||||
Optional<Book> findById(long id);
|
||||
|
||||
List<Book> findAll();
|
||||
|
||||
Book insert(String title, long authorId, List<Long> genresIds);
|
||||
|
||||
Book update(long id, String title, long authorId, List<Long> genresIds);
|
||||
|
||||
void deleteById(long id);
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
package ru.otus.hw.services;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.otus.hw.exceptions.EntityNotFoundException;
|
||||
import ru.otus.hw.models.Book;
|
||||
import ru.otus.hw.repositories.AuthorRepository;
|
||||
import ru.otus.hw.repositories.BookRepository;
|
||||
import ru.otus.hw.repositories.GenreRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class BookServiceImpl implements BookService {
|
||||
private final AuthorRepository authorRepository;
|
||||
|
||||
private final GenreRepository genreRepository;
|
||||
|
||||
private final BookRepository bookRepository;
|
||||
|
||||
@Override
|
||||
public Optional<Book> findById(long id) {
|
||||
return bookRepository.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Book> findAll() {
|
||||
return bookRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Book insert(String title, long authorId, List<Long> genresIds) {
|
||||
return save(0, title, authorId, genresIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Book update(long id, String title, long authorId, List<Long> genresIds) {
|
||||
return save(id, title, authorId, genresIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(long id) {
|
||||
bookRepository.deleteById(id);
|
||||
}
|
||||
|
||||
private Book save(long id, String title, long authorId, List<Long> genresIds) {
|
||||
var author = authorRepository.findById(authorId)
|
||||
.orElseThrow(() -> new EntityNotFoundException("Author with id %d not found".formatted(authorId)));
|
||||
var genres = genreRepository.findAllByIds(genresIds);
|
||||
if (isEmpty(genres)) {
|
||||
throw new EntityNotFoundException("Genres with ids %s not found".formatted(genresIds));
|
||||
}
|
||||
var book = new Book(id, title, author, genres);
|
||||
return bookRepository.save(book);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
insert into authors(full_name)
|
||||
values ('Author_1'), ('Author_2'), ('Author_3');
|
||||
|
||||
insert into genres(name)
|
||||
values ('Genre_1'), ('Genre_2'), ('Genre_3'),
|
||||
('Genre_4'), ('Genre_5'), ('Genre_6');
|
||||
|
||||
insert into books(title, author_id)
|
||||
values ('BookTitle_1', 1), ('BookTitle_2', 2), ('BookTitle_3', 3);
|
||||
|
||||
insert into books_genres(book_id, genre_id)
|
||||
values (1, 1), (1, 2),
|
||||
(2, 3), (2, 4),
|
||||
(3, 5), (3, 6);
|
||||
@@ -1,24 +0,0 @@
|
||||
create table authors (
|
||||
id bigserial,
|
||||
full_name varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table genres (
|
||||
id bigserial,
|
||||
name varchar(255),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table books (
|
||||
id bigserial,
|
||||
title varchar(255),
|
||||
author_id bigint references authors (id) on delete cascade,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table books_genres (
|
||||
book_id bigint references books(id) on delete cascade,
|
||||
genre_id bigint references genres(id) on delete cascade,
|
||||
primary key (book_id, genre_id)
|
||||
);
|
||||
-134
@@ -1,134 +0,0 @@
|
||||
package ru.otus.hw.repositories;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import ru.otus.hw.models.Author;
|
||||
import ru.otus.hw.models.Book;
|
||||
import ru.otus.hw.models.Genre;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@DisplayName("Репозиторий на основе Jdbc для работы с книгами ")
|
||||
@JdbcTest
|
||||
@Import({BookRepositoryJdbc.class, GenreRepositoryJdbc.class})
|
||||
class BookRepositoryJdbcTest {
|
||||
|
||||
@Autowired
|
||||
private BookRepositoryJdbc repositoryJdbc;
|
||||
|
||||
private List<Author> dbAuthors;
|
||||
|
||||
private List<Genre> dbGenres;
|
||||
|
||||
private List<Book> dbBooks;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
dbAuthors = getDbAuthors();
|
||||
dbGenres = getDbGenres();
|
||||
dbBooks = getDbBooks(dbAuthors, dbGenres);
|
||||
}
|
||||
|
||||
@DisplayName("должен загружать книгу по id")
|
||||
@ParameterizedTest
|
||||
@MethodSource("getDbBooks")
|
||||
void shouldReturnCorrectBookById(Book expectedBook) {
|
||||
var actualBook = repositoryJdbc.findById(expectedBook.getId());
|
||||
assertThat(actualBook).isPresent()
|
||||
.get()
|
||||
.isEqualTo(expectedBook);
|
||||
}
|
||||
|
||||
@DisplayName("должен загружать список всех книг")
|
||||
@Test
|
||||
void shouldReturnCorrectBooksList() {
|
||||
var actualBooks = repositoryJdbc.findAll();
|
||||
var expectedBooks = dbBooks;
|
||||
|
||||
assertThat(actualBooks).containsExactlyElementsOf(expectedBooks);
|
||||
actualBooks.forEach(System.out::println);
|
||||
}
|
||||
|
||||
@DisplayName("должен сохранять новую книгу")
|
||||
@Test
|
||||
void shouldSaveNewBook() {
|
||||
var expectedBook = new Book(0, "BookTitle_10500", dbAuthors.get(0),
|
||||
List.of(dbGenres.get(0), dbGenres.get(2)));
|
||||
var returnedBook = repositoryJdbc.save(expectedBook);
|
||||
assertThat(returnedBook).isNotNull()
|
||||
.matches(book -> book.getId() > 0)
|
||||
.usingRecursiveComparison().ignoringExpectedNullFields().isEqualTo(expectedBook);
|
||||
|
||||
assertThat(repositoryJdbc.findById(returnedBook.getId()))
|
||||
.isPresent()
|
||||
.get()
|
||||
.isEqualTo(returnedBook);
|
||||
}
|
||||
|
||||
@DisplayName("должен сохранять измененную книгу")
|
||||
@Test
|
||||
void shouldSaveUpdatedBook() {
|
||||
var expectedBook = new Book(1L, "BookTitle_10500", dbAuthors.get(2),
|
||||
List.of(dbGenres.get(4), dbGenres.get(5)));
|
||||
|
||||
assertThat(repositoryJdbc.findById(expectedBook.getId()))
|
||||
.isPresent()
|
||||
.get()
|
||||
.isNotEqualTo(expectedBook);
|
||||
|
||||
var returnedBook = repositoryJdbc.save(expectedBook);
|
||||
assertThat(returnedBook).isNotNull()
|
||||
.matches(book -> book.getId() > 0)
|
||||
.usingRecursiveComparison().ignoringExpectedNullFields().isEqualTo(expectedBook);
|
||||
|
||||
assertThat(repositoryJdbc.findById(returnedBook.getId()))
|
||||
.isPresent()
|
||||
.get()
|
||||
.isEqualTo(returnedBook);
|
||||
}
|
||||
|
||||
@DisplayName("должен удалять книгу по id ")
|
||||
@Test
|
||||
void shouldDeleteBook() {
|
||||
assertThat(repositoryJdbc.findById(1L)).isPresent();
|
||||
repositoryJdbc.deleteById(1L);
|
||||
assertThat(repositoryJdbc.findById(1L)).isEmpty();
|
||||
}
|
||||
|
||||
private static List<Author> getDbAuthors() {
|
||||
return IntStream.range(1, 4).boxed()
|
||||
.map(id -> new Author(id, "Author_" + id))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static List<Genre> getDbGenres() {
|
||||
return IntStream.range(1, 7).boxed()
|
||||
.map(id -> new Genre(id, "Genre_" + id))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static List<Book> getDbBooks(List<Author> dbAuthors, List<Genre> dbGenres) {
|
||||
return IntStream.range(1, 4).boxed()
|
||||
.map(id -> new Book(id,
|
||||
"BookTitle_" + id,
|
||||
dbAuthors.get(id - 1),
|
||||
dbGenres.subList((id - 1) * 2, (id - 1) * 2 + 2)
|
||||
))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static List<Book> getDbBooks() {
|
||||
var dbAuthors = getDbAuthors();
|
||||
var dbGenres = getDbGenres();
|
||||
return getDbBooks(dbAuthors, dbGenres);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
insert into authors(full_name)
|
||||
values ('Author_1'), ('Author_2'), ('Author_3');
|
||||
|
||||
insert into genres(name)
|
||||
values ('Genre_1'), ('Genre_2'), ('Genre_3'),
|
||||
('Genre_4'), ('Genre_5'), ('Genre_6');
|
||||
|
||||
insert into books(title, author_id)
|
||||
values ('BookTitle_1', 1), ('BookTitle_2', 2), ('BookTitle_3', 3);
|
||||
|
||||
insert into books_genres(book_id, genre_id)
|
||||
values (1, 1), (1, 2),
|
||||
(2, 3), (2, 4),
|
||||
(3, 5), (3, 6);
|
||||
@@ -16,7 +16,6 @@ HELP.md
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
spring-shell.log
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<version>3.1.5</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
package ru.otus.hw.commands;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import ru.otus.hw.converters.AuthorConverter;
|
||||
import ru.otus.hw.services.AuthorService;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@ShellComponent
|
||||
public class AuthorCommands {
|
||||
|
||||
private final AuthorService authorService;
|
||||
|
||||
private final AuthorConverter authorConverter;
|
||||
|
||||
@ShellMethod(value = "Find all authors", key = "aa")
|
||||
public String findAllAuthors() {
|
||||
return authorService.findAll().stream()
|
||||
.map(authorConverter::authorToString)
|
||||
.collect(Collectors.joining("," + System.lineSeparator()));
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
package ru.otus.hw.commands;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import ru.otus.hw.converters.GenreConverter;
|
||||
import ru.otus.hw.services.GenreService;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@ShellComponent
|
||||
public class GenreCommands {
|
||||
|
||||
private final GenreService genreService;
|
||||
|
||||
private final GenreConverter genreConverter;
|
||||
|
||||
@ShellMethod(value = "Find all genres", key = "ag")
|
||||
public String findAllGenres() {
|
||||
return genreService.findAll().stream()
|
||||
.map(genreConverter::genreToString)
|
||||
.collect(Collectors.joining("," + System.lineSeparator()));
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
package ru.otus.hw.converters;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.otus.hw.models.Author;
|
||||
|
||||
@Component
|
||||
public class AuthorConverter {
|
||||
public String authorToString(Author author) {
|
||||
return "Id: %d, FullName: %s".formatted(author.getId(), author.getFullName());
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
package ru.otus.hw.converters;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.otus.hw.models.Genre;
|
||||
|
||||
@Component
|
||||
public class GenreConverter {
|
||||
public String genreToString(Genre genre) {
|
||||
return "Id: %d, Name: %s".formatted(genre.getId(), genre.getName());
|
||||
}
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
package ru.otus.hw.exceptions;
|
||||
|
||||
public class EntityNotFoundException extends RuntimeException {
|
||||
public EntityNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package ru.otus.hw.models;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Author {
|
||||
private long id;
|
||||
|
||||
private String fullName;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package ru.otus.hw.models;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Genre {
|
||||
private long id;
|
||||
|
||||
private String name;
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
package ru.otus.hw.repositories;
|
||||
|
||||
import ru.otus.hw.models.Author;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface AuthorRepository {
|
||||
List<Author> findAll();
|
||||
|
||||
Optional<Author> findById(long id);
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
package ru.otus.hw.repositories;
|
||||
|
||||
import ru.otus.hw.models.Book;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface BookRepository {
|
||||
Optional<Book> findById(long id);
|
||||
|
||||
List<Book> findAll();
|
||||
|
||||
Book save(Book book);
|
||||
|
||||
void deleteById(long id);
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
package ru.otus.hw.services;
|
||||
|
||||
import ru.otus.hw.models.Author;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AuthorService {
|
||||
List<Author> findAll();
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
package ru.otus.hw.services;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.otus.hw.models.Author;
|
||||
import ru.otus.hw.repositories.AuthorRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class AuthorServiceImpl implements AuthorService {
|
||||
private final AuthorRepository authorRepository;
|
||||
|
||||
@Override
|
||||
public List<Author> findAll() {
|
||||
return authorRepository.findAll();
|
||||
}
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
package ru.otus.hw.services;
|
||||
|
||||
import ru.otus.hw.models.Genre;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface GenreService {
|
||||
List<Genre> findAll();
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
package ru.otus.hw.services;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.otus.hw.models.Genre;
|
||||
import ru.otus.hw.repositories.GenreRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class GenreServiceImpl implements GenreService {
|
||||
private final GenreRepository genreRepository;
|
||||
|
||||
@Override
|
||||
public List<Genre> findAll() {
|
||||
return genreRepository.findAll();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:h2:mem:maindb
|
||||
sql:
|
||||
init:
|
||||
mode: always
|
||||
data-locations: data.sql
|
||||
schema-locations: schema.sql
|
||||
@@ -1,8 +0,0 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:h2:mem:testdb
|
||||
sql:
|
||||
init:
|
||||
mode: always
|
||||
data-locations: data.sql
|
||||
schema-locations: schema.sql
|
||||
@@ -16,7 +16,6 @@ HELP.md
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
spring-shell.log
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<version>3.1.5</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
+3
@@ -8,6 +8,7 @@ import ru.otus.hw.services.BookService;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings({"SpellCheckingInspection", "unused"})
|
||||
@RequiredArgsConstructor
|
||||
@ShellComponent
|
||||
public class BookCommands {
|
||||
@@ -30,12 +31,14 @@ public class BookCommands {
|
||||
.orElse("Book with id %d not found".formatted(id));
|
||||
}
|
||||
|
||||
// bins newBook 1 1
|
||||
@ShellMethod(value = "Insert book", key = "bins")
|
||||
public String insertBook(String title, long authorId, long genreId) {
|
||||
var savedBook = bookService.insert(title, authorId, genreId);
|
||||
return bookConverter.bookToString(savedBook);
|
||||
}
|
||||
|
||||
// bupd 4 editedBook 3 2
|
||||
@ShellMethod(value = "Update book", key = "bupd")
|
||||
public String updateBook(long id, String title, long authorId, long genreId) {
|
||||
var savedBook = bookService.update(id, title, authorId, genreId);
|
||||
+1
-1
@@ -11,7 +11,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public class AuthorRepositoryJdbc implements AuthorRepository {
|
||||
public class JdbcAuthorRepository implements AuthorRepository {
|
||||
|
||||
@Override
|
||||
public List<Author> findAll() {
|
||||
+2
-1
@@ -12,7 +12,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public class BookRepositoryJdbc implements BookRepository {
|
||||
public class JdbcBookRepository implements BookRepository {
|
||||
|
||||
@Override
|
||||
public Optional<Book> findById(long id) {
|
||||
@@ -49,6 +49,7 @@ public class BookRepositoryJdbc implements BookRepository {
|
||||
|
||||
private Book update(Book book) {
|
||||
//...
|
||||
// Выбросить EntityNotFoundException если не обновлено ни одной записи в БД
|
||||
return book;
|
||||
}
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public class GenreRepositoryJdbc implements GenreRepository {
|
||||
public class JdbcGenreRepository implements GenreRepository {
|
||||
|
||||
@Override
|
||||
public List<Genre> findAll() {
|
||||
+3
-3
@@ -19,11 +19,11 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@DisplayName("Репозиторий на основе Jdbc для работы с книгами ")
|
||||
@JdbcTest
|
||||
@Import({BookRepositoryJdbc.class, GenreRepositoryJdbc.class})
|
||||
class BookRepositoryJdbcTest {
|
||||
@Import({JdbcBookRepository.class, JdbcGenreRepository.class})
|
||||
class JdbcBookRepositoryTest {
|
||||
|
||||
@Autowired
|
||||
private BookRepositoryJdbc repositoryJdbc;
|
||||
private JdbcBookRepository repositoryJdbc;
|
||||
|
||||
private List<Author> dbAuthors;
|
||||
|
||||
Reference in New Issue
Block a user