From bddcdcff211d67656ce311a01384698cd9405ace Mon Sep 17 00:00:00 2001 From: Liubomyr Kniazkyi Date: Sat, 5 Aug 2023 20:43:55 +0300 Subject: [PATCH 1/2] created Book model, implemented BookDao for working with SQL DB --- pom.xml | 8 ++ src/main/java/mate/academy/Main.java | 29 ++++ .../connection/util/ConnectionUtil.java | 28 ++++ src/main/java/mate/academy/dao/BookDao.java | 13 ++ .../java/mate/academy/dao/BookDaoImpl.java | 133 ++++++++++++++++++ .../exception/DataProcessingException.java | 7 + src/main/java/mate/academy/model/Book.java | 53 +++++++ src/main/resources/init_db.sql | 6 + 8 files changed, 277 insertions(+) create mode 100644 src/main/java/mate/academy/connection/util/ConnectionUtil.java create mode 100644 src/main/java/mate/academy/dao/BookDao.java create mode 100644 src/main/java/mate/academy/dao/BookDaoImpl.java create mode 100644 src/main/java/mate/academy/exception/DataProcessingException.java create mode 100644 src/main/java/mate/academy/model/Book.java create mode 100644 src/main/resources/init_db.sql diff --git a/pom.xml b/pom.xml index 969b5f3e..870c3d8a 100644 --- a/pom.xml +++ b/pom.xml @@ -14,4 +14,12 @@ UTF-8 + + + com.mysql + mysql-connector-j + 8.1.0 + + + \ No newline at end of file diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java index 0058fbf9..9b06b190 100644 --- a/src/main/java/mate/academy/Main.java +++ b/src/main/java/mate/academy/Main.java @@ -1,7 +1,36 @@ package mate.academy; +import mate.academy.dao.BookDao; +import mate.academy.lib.Injector; +import mate.academy.model.Book; +import java.math.BigDecimal; + public class Main { + private static final Injector injector = Injector.getInstance("mate.academy"); + public static void main(String[] args) { + BookDao bookDao = (BookDao) injector.getInstance(BookDao.class); + Book marquezBook = new Book("One Hundred Years of Solitude", new BigDecimal(571)); + Book rowlingBook = new Book("Harry Potter and the Half-Blood Prince", new BigDecimal(250)); + Book secondMarquezBook = new Book(2L, "No One Writes to the Colonel", new BigDecimal(450)); + +// Book bookUpdated = bookDao.create(marquezBook); +// Book bookUpdated2 = bookDao.create(rowlingBook); +// System.out.println(bookUpdated); +// System.out.println(bookUpdated2); +// +// Optional bookById = bookDao.findById(4L); +// System.out.println(bookById); +// +// List allBooks = bookDao.findAll(); +// for (Book element : allBooks) { +// System.out.println(element); +// } +// +// Book updateBook = bookDao.update(secondMarquezBook); +// System.out.println(updateBook); + boolean deleteBook = bookDao.deleteById(1L); + System.out.println(deleteBook); } } diff --git a/src/main/java/mate/academy/connection/util/ConnectionUtil.java b/src/main/java/mate/academy/connection/util/ConnectionUtil.java new file mode 100644 index 00000000..9d76c053 --- /dev/null +++ b/src/main/java/mate/academy/connection/util/ConnectionUtil.java @@ -0,0 +1,28 @@ +package mate.academy.connection.util; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +public class ConnectionUtil { + private static final String DB_URL = "jdbc:mysql://localhost:3306/test"; + private static final Properties DB_PROPERTIES; + private static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; + private static final String JDBC_DRIVER_EXCEPTION = "Cannot load JDBC driver"; + + static { + DB_PROPERTIES = new Properties(); + DB_PROPERTIES.put("user", "root"); + DB_PROPERTIES.put("password", "Root1234"); + try { + Class.forName(JDBC_DRIVER); + } catch (ClassNotFoundException e) { + throw new RuntimeException(JDBC_DRIVER_EXCEPTION, e); + } + } + + public static Connection getConnection() throws SQLException { + return DriverManager.getConnection(DB_URL, DB_PROPERTIES); + } +} 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..9ce14471 --- /dev/null +++ b/src/main/java/mate/academy/dao/BookDao.java @@ -0,0 +1,13 @@ +package mate.academy.dao; + +import mate.academy.model.Book; +import java.util.List; +import java.util.Optional; + +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..1f99f567 --- /dev/null +++ b/src/main/java/mate/academy/dao/BookDaoImpl.java @@ -0,0 +1,133 @@ +package mate.academy.dao; + +import mate.academy.connection.util.ConnectionUtil; +import mate.academy.exception.DataProcessingException; +import mate.academy.lib.Dao; +import mate.academy.model.Book; +import java.math.BigDecimal; +import java.sql.Connection; +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; + +@Dao +public class BookDaoImpl implements BookDao { + private static final String AT_LEAST_ONE_ROW_EXCEPTION + = "Expected to insert at least one row, but inserted 0 rows"; + private static final String ADD_BOOK_EXCEPTION = "Cannot add new book: "; + private static final String GET_BOOK_EXCEPTION = "Cannot get a book by id: "; + private static final String GET_ALL_BOOKS_EXCEPTION = "Cannot get books"; + private static final String UPDATE_BOOK_EXCEPTION = "Cannot update book by id "; + private static final String DELETE_BOOK_EXCEPTION = "Cannot delete by id "; + private static final String NO_BOOK_EXCEPTION = "There are no book by id: "; + private static final String NULL_FIELDS_EXCEPTION = "Title name or price cannot be null"; + private static final String NEGATIVE_ID_EXCEPTION = "ID cannot be negative"; + private static final String NO_RECORDS_EXCEPTION = "There are no records in DB"; + private static final int LESS_THAN_ONE = 1; + private static final int AT_LEAST_ONE = 0; + private static final int LESS_THAN_ZERO = 0; + private static final int ZERO = 0; + + @Override + public Book create(Book book) { + if (book.getTitle() == null || book.getPrice() == null) { + throw new RuntimeException(NULL_FIELDS_EXCEPTION); + } + String sqlUpdate = "INSERT INTO books (title, price) VALUES (?, ?)"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sqlUpdate, Statement.RETURN_GENERATED_KEYS)) { + statement.setString(1, book.getTitle()); + statement.setBigDecimal(2, book.getPrice()); + int affectedRows = statement.executeUpdate(); + if (affectedRows < LESS_THAN_ONE) { + throw new RuntimeException(AT_LEAST_ONE_ROW_EXCEPTION); + } + ResultSet generatedKeys = statement.getGeneratedKeys(); + if (generatedKeys.next()) { + Long id = generatedKeys.getObject(1, Long.class); + book.setId(id); + } + return book; + } catch (SQLException e) { + throw new DataProcessingException(ADD_BOOK_EXCEPTION + book, e); + } + } + + @Override + public Optional findById(Long id) { + if (id < LESS_THAN_ZERO) { + throw new RuntimeException(NEGATIVE_ID_EXCEPTION); + } + String sqlQuery = "SELECT * FROM books WHERE id = ?"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sqlQuery)) { + statement.setLong(1, id); + ResultSet resultSet = statement.executeQuery(); + if (resultSet.next()) { + String model = resultSet.getString("title"); + BigDecimal price = resultSet.getObject("price", BigDecimal.class); + return Optional.of(new Book(id, model, price)); + } + throw new RuntimeException(NO_BOOK_EXCEPTION + id); + } catch (SQLException e) { + throw new DataProcessingException(GET_BOOK_EXCEPTION, e); + } + } + + @Override + public List findAll() { + List books = new ArrayList<>(); + String sqlQuery = "SELECT * FROM books"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sqlQuery)) { + ResultSet resultSet = statement.executeQuery(); + while (resultSet.next()) { + Long id = resultSet.getObject("id", Long.class); + String model = resultSet.getString("title"); + BigDecimal price = resultSet.getObject("price", BigDecimal.class); + books.add(new Book(id, model, price)); + } + if (books.size() == ZERO) { + throw new RuntimeException(NO_RECORDS_EXCEPTION); + } + return books; + } catch (SQLException e) { + throw new DataProcessingException(GET_ALL_BOOKS_EXCEPTION, e); + } + } + + @Override + public Book update(Book book) { + if (book.getTitle() == null || book.getPrice() == null) { + throw new RuntimeException(NULL_FIELDS_EXCEPTION); + } + String sqlUpdate = "UPDATE books SET price = ?, title = ? WHERE id = ?"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sqlUpdate)) { + statement.setBigDecimal(1, book.getPrice()); + statement.setString(2, book.getTitle()); + statement.setLong(3, book.getId()); + statement.executeUpdate(); + return book; + } catch (SQLException e) { + throw new DataProcessingException(UPDATE_BOOK_EXCEPTION + book.getId(), e); + } + } + + @Override + public boolean deleteById(Long id) { + String sqlUpdate = "DELETE FROM books WHERE id = ?"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sqlUpdate)) { + statement.setLong(1, id); + int affectedRows = statement.executeUpdate(); + return affectedRows > AT_LEAST_ONE; + } catch (SQLException e) { + throw new DataProcessingException(DELETE_BOOK_EXCEPTION + id, e); + } + } +} diff --git a/src/main/java/mate/academy/exception/DataProcessingException.java b/src/main/java/mate/academy/exception/DataProcessingException.java new file mode 100644 index 00000000..27877dca --- /dev/null +++ b/src/main/java/mate/academy/exception/DataProcessingException.java @@ -0,0 +1,7 @@ +package mate.academy.exception; + +public class DataProcessingException extends RuntimeException{ + public DataProcessingException(String message, Throwable ex) { + super(message, ex); + } +} diff --git a/src/main/java/mate/academy/model/Book.java b/src/main/java/mate/academy/model/Book.java new file mode 100644 index 00000000..430f40d4 --- /dev/null +++ b/src/main/java/mate/academy/model/Book.java @@ -0,0 +1,53 @@ +package mate.academy.model; + +import java.math.BigDecimal; + +public class Book { + private Long id; + private String title; + private BigDecimal price; + + public Book(String title, BigDecimal price) { + this.title = title; + this.price = price; + } + + public Book(Long id, String title, BigDecimal price) { + this.id = id; + this.title = title; + this.price = price; + } + + 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/resources/init_db.sql b/src/main/resources/init_db.sql new file mode 100644 index 00000000..e0230175 --- /dev/null +++ b/src/main/resources/init_db.sql @@ -0,0 +1,6 @@ +CREATE TABLE `books` ( +`id` BIGINT NOT NULL AUTO_INCREMENT, +`title` VARCHAR(255), +`price` INT, +PRIMARY KEY (`id`) +); From bae0f048192bddccd9c935b70ba0e2844de573e4 Mon Sep 17 00:00:00 2001 From: Liubomyr Kniazkyi Date: Sun, 6 Aug 2023 16:01:59 +0300 Subject: [PATCH 2/2] added fixes after review --- src/main/java/mate/academy/Main.java | 10 ++-- src/main/java/mate/academy/dao/BookDao.java | 4 ++ .../java/mate/academy/dao/BookDaoImpl.java | 60 ++++++------------- 3 files changed, 27 insertions(+), 47 deletions(-) diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java index 9b06b190..9fea0bc9 100644 --- a/src/main/java/mate/academy/Main.java +++ b/src/main/java/mate/academy/Main.java @@ -4,6 +4,8 @@ import mate.academy.lib.Injector; import mate.academy.model.Book; import java.math.BigDecimal; +import java.util.List; +import java.util.Optional; public class Main { private static final Injector injector = Injector.getInstance("mate.academy"); @@ -11,7 +13,7 @@ public class Main { public static void main(String[] args) { BookDao bookDao = (BookDao) injector.getInstance(BookDao.class); Book marquezBook = new Book("One Hundred Years of Solitude", new BigDecimal(571)); - Book rowlingBook = new Book("Harry Potter and the Half-Blood Prince", new BigDecimal(250)); + Book rowlingBook = new Book(5L, "Harry Potter and the Half-Blood Prince", new BigDecimal(250)); Book secondMarquezBook = new Book(2L, "No One Writes to the Colonel", new BigDecimal(450)); // Book bookUpdated = bookDao.create(marquezBook); @@ -19,7 +21,7 @@ public static void main(String[] args) { // System.out.println(bookUpdated); // System.out.println(bookUpdated2); // -// Optional bookById = bookDao.findById(4L); +// Optional bookById = bookDao.findById(3L); // System.out.println(bookById); // // List allBooks = bookDao.findAll(); @@ -27,10 +29,10 @@ public static void main(String[] args) { // System.out.println(element); // } // -// Book updateBook = bookDao.update(secondMarquezBook); +// Book updateBook = bookDao.update(rowlingBook); // System.out.println(updateBook); - boolean deleteBook = bookDao.deleteById(1L); + boolean deleteBook = bookDao.deleteById(4L); System.out.println(deleteBook); } } diff --git a/src/main/java/mate/academy/dao/BookDao.java b/src/main/java/mate/academy/dao/BookDao.java index 9ce14471..5219aa0b 100644 --- a/src/main/java/mate/academy/dao/BookDao.java +++ b/src/main/java/mate/academy/dao/BookDao.java @@ -6,8 +6,12 @@ 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 index 1f99f567..e42faa9c 100644 --- a/src/main/java/mate/academy/dao/BookDaoImpl.java +++ b/src/main/java/mate/academy/dao/BookDaoImpl.java @@ -16,36 +16,16 @@ @Dao public class BookDaoImpl implements BookDao { - private static final String AT_LEAST_ONE_ROW_EXCEPTION - = "Expected to insert at least one row, but inserted 0 rows"; - private static final String ADD_BOOK_EXCEPTION = "Cannot add new book: "; - private static final String GET_BOOK_EXCEPTION = "Cannot get a book by id: "; - private static final String GET_ALL_BOOKS_EXCEPTION = "Cannot get books"; - private static final String UPDATE_BOOK_EXCEPTION = "Cannot update book by id "; - private static final String DELETE_BOOK_EXCEPTION = "Cannot delete by id "; - private static final String NO_BOOK_EXCEPTION = "There are no book by id: "; - private static final String NULL_FIELDS_EXCEPTION = "Title name or price cannot be null"; - private static final String NEGATIVE_ID_EXCEPTION = "ID cannot be negative"; - private static final String NO_RECORDS_EXCEPTION = "There are no records in DB"; - private static final int LESS_THAN_ONE = 1; private static final int AT_LEAST_ONE = 0; - private static final int LESS_THAN_ZERO = 0; - private static final int ZERO = 0; @Override public Book create(Book book) { - if (book.getTitle() == null || book.getPrice() == null) { - throw new RuntimeException(NULL_FIELDS_EXCEPTION); - } String sqlUpdate = "INSERT INTO books (title, price) VALUES (?, ?)"; try (Connection connection = ConnectionUtil.getConnection(); PreparedStatement statement = connection.prepareStatement(sqlUpdate, Statement.RETURN_GENERATED_KEYS)) { statement.setString(1, book.getTitle()); statement.setBigDecimal(2, book.getPrice()); - int affectedRows = statement.executeUpdate(); - if (affectedRows < LESS_THAN_ONE) { - throw new RuntimeException(AT_LEAST_ONE_ROW_EXCEPTION); - } + statement.executeUpdate(); ResultSet generatedKeys = statement.getGeneratedKeys(); if (generatedKeys.next()) { Long id = generatedKeys.getObject(1, Long.class); @@ -53,28 +33,24 @@ public Book create(Book book) { } return book; } catch (SQLException e) { - throw new DataProcessingException(ADD_BOOK_EXCEPTION + book, e); + throw new DataProcessingException("Cannot add new book: " + book, e); } } @Override public Optional findById(Long id) { - if (id < LESS_THAN_ZERO) { - throw new RuntimeException(NEGATIVE_ID_EXCEPTION); - } + Book book = null; String sqlQuery = "SELECT * FROM books WHERE id = ?"; try (Connection connection = ConnectionUtil.getConnection(); PreparedStatement statement = connection.prepareStatement(sqlQuery)) { statement.setLong(1, id); ResultSet resultSet = statement.executeQuery(); if (resultSet.next()) { - String model = resultSet.getString("title"); - BigDecimal price = resultSet.getObject("price", BigDecimal.class); - return Optional.of(new Book(id, model, price)); + book = parseBook(resultSet); } - throw new RuntimeException(NO_BOOK_EXCEPTION + id); + return Optional.ofNullable(book); } catch (SQLException e) { - throw new DataProcessingException(GET_BOOK_EXCEPTION, e); + throw new DataProcessingException("Cannot get a book by id: " + id, e); } } @@ -86,25 +62,16 @@ public List findAll() { PreparedStatement statement = connection.prepareStatement(sqlQuery)) { ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { - Long id = resultSet.getObject("id", Long.class); - String model = resultSet.getString("title"); - BigDecimal price = resultSet.getObject("price", BigDecimal.class); - books.add(new Book(id, model, price)); - } - if (books.size() == ZERO) { - throw new RuntimeException(NO_RECORDS_EXCEPTION); + books.add(parseBook(resultSet)); } return books; } catch (SQLException e) { - throw new DataProcessingException(GET_ALL_BOOKS_EXCEPTION, e); + throw new DataProcessingException("Cannot get books", e); } } @Override public Book update(Book book) { - if (book.getTitle() == null || book.getPrice() == null) { - throw new RuntimeException(NULL_FIELDS_EXCEPTION); - } String sqlUpdate = "UPDATE books SET price = ?, title = ? WHERE id = ?"; try (Connection connection = ConnectionUtil.getConnection(); PreparedStatement statement = connection.prepareStatement(sqlUpdate)) { @@ -114,7 +81,7 @@ public Book update(Book book) { statement.executeUpdate(); return book; } catch (SQLException e) { - throw new DataProcessingException(UPDATE_BOOK_EXCEPTION + book.getId(), e); + throw new DataProcessingException("Cannot update a book by id " + book.getId(), e); } } @@ -127,7 +94,14 @@ public boolean deleteById(Long id) { int affectedRows = statement.executeUpdate(); return affectedRows > AT_LEAST_ONE; } catch (SQLException e) { - throw new DataProcessingException(DELETE_BOOK_EXCEPTION + id, e); + throw new DataProcessingException("Cannot delete a book by id " + id, e); } } + + private Book parseBook(ResultSet resultSet) throws SQLException { + Long id = resultSet.getObject("id", Long.class); + String model = resultSet.getString("title"); + BigDecimal price = resultSet.getObject("price", BigDecimal.class); + return new Book(id, model, price); + } }