diff --git a/pom.xml b/pom.xml index 683e84ec..9e45dc54 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,14 @@ + + + com.mysql + mysql-connector-j + 8.4.0 + + + diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java index 0058fbf9..88f3de9a 100644 --- a/src/main/java/mate/academy/Main.java +++ b/src/main/java/mate/academy/Main.java @@ -1,7 +1,47 @@ package mate.academy; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import mate.academy.dao.BookDao; +import mate.academy.lib.Injector; +import mate.academy.models.Book; +import mate.academy.service.BookService; +import mate.academy.service.BookServiceImpl; + public class Main { + private static final Injector injector = Injector + .getInstance("mate.academy"); + private static final BigDecimal NEW_PRICE = new BigDecimal("120.50"); + public static void main(String[] args) { + BookDao bookDao = (BookDao) injector.getInstance(BookDao.class); + BookService bookService = new BookServiceImpl(bookDao); + + List savedBooks = new ArrayList<>(); + Map.of("Java", new BigDecimal(300), + "Python", new BigDecimal(200), + "C++", new BigDecimal(100)) + .forEach((title, price) -> { + Book currentBook = new Book(); + currentBook.setTitle(title); + currentBook.setPrice(price); + savedBooks.add(bookService.save(currentBook)); + }); + System.out.println("savedBooks = " + savedBooks); + + Book book = bookService.get(2L); + System.out.printf("Method get return: " + book); + + book.setPrice(book.getPrice().multiply(NEW_PRICE)); + book = bookService.update(book); + System.out.printf("Method update return: " + book); + + boolean isDeleteBook = bookService.delete(savedBooks.get(0)); + System.out.printf("Method delete return: " + isDeleteBook); + List bookList2 = bookService.getAll(); + System.out.printf("Method getAll return: " + bookList2.toString()); } } diff --git a/src/main/java/mate/academy/dao/BookDao.java b/src/main/java/mate/academy/dao/BookDao.java new file mode 100644 index 00000000..2b9c3353 --- /dev/null +++ b/src/main/java/mate/academy/dao/BookDao.java @@ -0,0 +1,18 @@ +package mate.academy.dao; + +import java.util.List; +import java.util.Optional; +import mate.academy.models.Book; + +public interface BookDao { + + Book create(Book book); + + Optional findById(Long id); + + List findAll(); + + Book update(Book book); + + boolean deleteById(Long id); +} diff --git a/src/main/java/mate/academy/dao/BookDaoImpl.java b/src/main/java/mate/academy/dao/BookDaoImpl.java new file mode 100644 index 00000000..d4c04093 --- /dev/null +++ b/src/main/java/mate/academy/dao/BookDaoImpl.java @@ -0,0 +1,121 @@ +package mate.academy.dao; + +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import mate.academy.exceptions.DataProcessingException; +import mate.academy.lib.Dao; +import mate.academy.models.Book; + +@Dao +public class BookDaoImpl implements BookDao { + @Override + public Book create(Book book) { + String sql = "INSERT INTO books (title, price) VALUE (?, ?)"; + try (PreparedStatement prepareStatement = ConnectionUtilImpl.getConnection() + .prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { + + prepareStatement.setString(1, book.getTitle()); + prepareStatement.setBigDecimal(2, book.getPrice()); + + if (prepareStatement.executeUpdate() > 1) { + book.setId(getIdFromResultSet(prepareStatement.getGeneratedKeys())); + return book; + } + throw new DataProcessingException("Can't save the new book: " + book); + } catch (SQLException e) { + throw new DataProcessingException("Can't save a book: " + book, e); + } + } + + @Override + public Optional findById(Long id) { + String sql = "SELECT * FROM books WHERE id = ?"; + try (PreparedStatement prepareStatement = ConnectionUtilImpl.getConnection() + .prepareStatement(sql)) { + + prepareStatement.setLong(1, id); + + return getBookFromResultSet(prepareStatement.executeQuery()); + } catch (SQLException e) { + throw new DataProcessingException("Can't get a book by id: " + id, e); + } + } + + @Override + public List findAll() { + String sql = "SELECT * FROM books"; + try (Statement statement = ConnectionUtilImpl.getConnection().createStatement()) { + + return getAllFromResultSet(statement.executeQuery(sql)); + } catch (SQLException e) { + throw new DataProcessingException("Can't get any books from the database", e); + } + } + + @Override + public Book update(Book book) { + String sql = "UPDATE books SET title = ?, price = ? WHERE id = ?"; + try (PreparedStatement prepareStatement = ConnectionUtilImpl.getConnection() + .prepareStatement(sql)) { + + prepareStatement.setString(1, book.getTitle()); + prepareStatement.setBigDecimal(2, book.getPrice()); + prepareStatement.setLong(3, book.getId()); + + if (prepareStatement.executeUpdate() > 1) { + return book; + } + throw new DataProcessingException("Can't update the book: " + book); + } catch (SQLException e) { + throw new DataProcessingException("Can't update the book: " + book, e); + } + } + + @Override + public boolean deleteById(Long id) { + String sql = "DELETE FROM books WHERE id = ?"; + try (PreparedStatement prepareStatement = ConnectionUtilImpl.getConnection() + .prepareStatement(sql)) { + + prepareStatement.setLong(1, id); + + return prepareStatement.executeUpdate() > 1; + } catch (SQLException e) { + throw new DataProcessingException("Can't delete the book by id: " + id, e); + } + } + + private Long getIdFromResultSet(ResultSet generatedKeys) throws SQLException { + if (generatedKeys.next()) { + return generatedKeys.getObject(1, Long.class); + } + throw new DataProcessingException("Can't writing the book to the database, missing ID"); + } + + private Optional getBookFromResultSet(ResultSet resultSet) throws SQLException { + if (resultSet.next()) { + Book book = new Book(); + + book.setId(resultSet.getObject("id", Long.class)); + book.setTitle(resultSet.getString("title")); + book.setPrice(resultSet.getObject("price", BigDecimal.class)); + + return Optional.of(book); + } + return Optional.empty(); + } + + private List getAllFromResultSet(ResultSet resultSet) throws SQLException { + List bookList = new ArrayList<>(); + do { + getBookFromResultSet(resultSet).ifPresent(bookList::add); + } while (resultSet.next()); + return bookList; + } +} diff --git a/src/main/java/mate/academy/dao/ConnectionUtil.java b/src/main/java/mate/academy/dao/ConnectionUtil.java new file mode 100644 index 00000000..70ecc1b5 --- /dev/null +++ b/src/main/java/mate/academy/dao/ConnectionUtil.java @@ -0,0 +1,4 @@ +package mate.academy.dao; + +public interface ConnectionUtil { +} diff --git a/src/main/java/mate/academy/dao/ConnectionUtilImpl.java b/src/main/java/mate/academy/dao/ConnectionUtilImpl.java new file mode 100644 index 00000000..69e31ba5 --- /dev/null +++ b/src/main/java/mate/academy/dao/ConnectionUtilImpl.java @@ -0,0 +1,30 @@ +package mate.academy.dao; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +public class ConnectionUtilImpl implements ConnectionUtil { + private static final String USER = "root"; + private static final String PASSWORD = "illya"; + private static final String DB_URL = "jdbs.mysql://localhost:3306/my_db"; + private static final Properties DB_PROPERTIES; + + static { + DB_PROPERTIES = new Properties(); + DB_PROPERTIES.put("user", USER); + DB_PROPERTIES.put("password", PASSWORD); + + try { + Class.forName("com.mysql.cj.jdbs.Driver"); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Can not load JDBS driver", e); + } + } + + static Connection getConnection() throws SQLException { + return DriverManager.getConnection(DB_URL, DB_PROPERTIES); + } + +} diff --git a/src/main/java/mate/academy/exceptions/DataProcessingException.java b/src/main/java/mate/academy/exceptions/DataProcessingException.java new file mode 100644 index 00000000..e5a244c1 --- /dev/null +++ b/src/main/java/mate/academy/exceptions/DataProcessingException.java @@ -0,0 +1,12 @@ +package mate.academy.exceptions; + +public class DataProcessingException extends RuntimeException { + public DataProcessingException(String message) { + super(message); + } + + public DataProcessingException(String message, Throwable cause) { + super(message, cause); + + } +} diff --git a/src/main/java/mate/academy/lib/Dao.java b/src/main/java/mate/academy/lib/Dao.java index f558d09a..22f45911 100644 --- a/src/main/java/mate/academy/lib/Dao.java +++ b/src/main/java/mate/academy/lib/Dao.java @@ -1,8 +1,4 @@ package mate.academy.lib; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.RUNTIME) public @interface Dao { } diff --git a/src/main/java/mate/academy/models/Book.java b/src/main/java/mate/academy/models/Book.java new file mode 100644 index 00000000..de901713 --- /dev/null +++ b/src/main/java/mate/academy/models/Book.java @@ -0,0 +1,45 @@ +package mate.academy.models; + +import java.math.BigDecimal; + +public class Book { + private Long id; + private String title; + private BigDecimal price; + + public Book() { + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + @Override + public String toString() { + return "Book{" + + "id=" + id + + ", title='" + title + '\'' + + ", price=" + price + + '}'; + } +} diff --git a/src/main/java/mate/academy/service/BookService.java b/src/main/java/mate/academy/service/BookService.java new file mode 100644 index 00000000..c25e2937 --- /dev/null +++ b/src/main/java/mate/academy/service/BookService.java @@ -0,0 +1,16 @@ +package mate.academy.service; + +import java.util.List; +import mate.academy.models.Book; + +public interface BookService { + Book save(Book book); + + Book get(Long id); + + List getAll(); + + Book update(Book book); + + boolean delete(Book book); +} diff --git a/src/main/java/mate/academy/service/BookServiceImpl.java b/src/main/java/mate/academy/service/BookServiceImpl.java new file mode 100644 index 00000000..3a4717d8 --- /dev/null +++ b/src/main/java/mate/academy/service/BookServiceImpl.java @@ -0,0 +1,60 @@ +package mate.academy.service; + +import java.util.List; +import mate.academy.dao.BookDao; +import mate.academy.exceptions.DataProcessingException; +import mate.academy.models.Book; + +public class BookServiceImpl implements BookService { + private final BookDao bookDao; + + public BookServiceImpl(BookDao bookDao) { + if (bookDao == null) { + throw new DataProcessingException("The argument (bookDao) is null"); + } + this.bookDao = bookDao; + } + + @Override + public Book save(Book book) { + if (book == null) { + throw new DataProcessingException("The argument (book) is null"); + } + return bookDao.create(book); + } + + @Override + public Book get(Long id) { + if (id == null) { + throw new DataProcessingException("The argument (id) is null"); + } + return bookDao.findById(id) + .orElseThrow(() -> new DataProcessingException("Can't find a book with id: " + + id)); + } + + @Override + public List getAll() { + List bookList = bookDao.findAll(); + if (bookList.isEmpty()) { + throw new DataProcessingException("Can't get any books from the database"); + } + return bookList; + } + + @Override + public Book update(Book book) { + if (book == null) { + throw new DataProcessingException("The argument (book) is null"); + } + return bookDao.update(book); + } + + @Override + public boolean delete(Book book) { + if (book == null || book.getId() == null) { + throw new DataProcessingException("The argument (book) or id is null"); + } + return bookDao.deleteById(book.getId()); + } +} diff --git a/src/main/resources/init_db.sql b/src/main/resources/init_db.sql new file mode 100644 index 00000000..b4dfc36e --- /dev/null +++ b/src/main/resources/init_db.sql @@ -0,0 +1,7 @@ +CREATE DATABASE `my_db`; +USE my_db; +CREATE TABLE books ( + id BIGINT PRIMARY KEY, + title VARCHAR(50), + price DECIMAL(10,2) + ); \ No newline at end of file