From fe4f09a216d092ecea95abc60f557d144f839045 Mon Sep 17 00:00:00 2001 From: Nikita Khilobok Date: Sun, 29 Sep 2024 20:04:40 +0300 Subject: [PATCH 1/3] hw is done, please check --- pom.xml | 7 ++ .../java/mate/academy/ConnectionUtil.java | 29 +++++ src/main/java/mate/academy/Main.java | 28 +++++ src/main/java/mate/academy/dao/BookDao.java | 19 +++ .../mate/academy/dao/impl/BookDaoImpl.java | 113 ++++++++++++++++++ src/main/java/mate/academy/lib/Injector.java | 8 +- src/main/java/mate/academy/model/Book.java | 51 ++++++++ .../service/DataProcessingException.java | 7 ++ src/main/resources/init_db.sql | 5 + 9 files changed, 263 insertions(+), 4 deletions(-) create mode 100644 src/main/java/mate/academy/ConnectionUtil.java create mode 100644 src/main/java/mate/academy/dao/BookDao.java create mode 100644 src/main/java/mate/academy/dao/impl/BookDaoImpl.java create mode 100644 src/main/java/mate/academy/model/Book.java create mode 100644 src/main/java/mate/academy/service/DataProcessingException.java create mode 100644 src/main/resources/init_db.sql diff --git a/pom.xml b/pom.xml index 683e84ec..a1ddac20 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,13 @@ + + + com.mysql + mysql-connector-j + 9.0.0 + + diff --git a/src/main/java/mate/academy/ConnectionUtil.java b/src/main/java/mate/academy/ConnectionUtil.java new file mode 100644 index 00000000..5261f2a0 --- /dev/null +++ b/src/main/java/mate/academy/ConnectionUtil.java @@ -0,0 +1,29 @@ +package mate.academy; + +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/jdbc_intro"; + private static final String USERNAME = "root"; + private static final String PASSWORD = "Nk102030!"; + private static final Properties DB_PROPERTIES; + + static { + DB_PROPERTIES = new Properties(); + DB_PROPERTIES.put("user", USERNAME); + DB_PROPERTIES.put("password", PASSWORD); + + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Can not load JDBC driver", e); + } + } + + public static Connection getConnection() throws SQLException { + return DriverManager.getConnection(DB_URL, DB_PROPERTIES); + } +} diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java index 0058fbf9..3fd58f5c 100644 --- a/src/main/java/mate/academy/Main.java +++ b/src/main/java/mate/academy/Main.java @@ -1,7 +1,35 @@ package mate.academy; +import java.math.BigDecimal; +import java.util.List; +import java.util.Optional; +import mate.academy.dao.BookDao; +import mate.academy.lib.Injector; +import mate.academy.model.Book; + 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 book = new Book(); + book.setTitle("NewTitle"); + book.setPrice(BigDecimal.valueOf(40)); + Book bookUpdated = bookDao.create(book); + System.out.println("Created: " + bookUpdated); + + Optional findById = bookDao.findById(book.getId()); + System.out.println("Found: " + findById); + + List list = bookDao.findAll(); + System.out.println("All lines: " + list); + + book.setTitle("Updated title"); + bookDao.update(book); + System.out.println("Updated: " + book); + boolean deleted = bookDao.deleteById(book.getId()); + System.out.println("Deleted: " + deleted); } } 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..acd8ca83 --- /dev/null +++ b/src/main/java/mate/academy/dao/BookDao.java @@ -0,0 +1,19 @@ +package mate.academy.dao; + +import java.util.List; +import java.util.Optional; +import mate.academy.lib.Dao; +import mate.academy.model.Book; + +@Dao +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/impl/BookDaoImpl.java b/src/main/java/mate/academy/dao/impl/BookDaoImpl.java new file mode 100644 index 00000000..a5c714e2 --- /dev/null +++ b/src/main/java/mate/academy/dao/impl/BookDaoImpl.java @@ -0,0 +1,113 @@ +package mate.academy.dao.impl; + +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; +import mate.academy.ConnectionUtil; +import mate.academy.dao.BookDao; +import mate.academy.lib.Dao; +import mate.academy.model.Book; +import mate.academy.service.DataProcessingException; + +@Dao +public class BookDaoImpl implements BookDao { + @Override + public Book create(Book book) { + String sql = "INSERT INTO books (title, price) VALUES (?, ?)"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sql, + Statement.RETURN_GENERATED_KEYS)) { + statement.setString(1, book.getTitle()); + statement.setBigDecimal(2, book.getPrice()); + + int affectedRows = statement.executeUpdate(); + if (affectedRows < 0) { + throw new DataProcessingException("Expected to insert at least one row," + + " but inserted 0 rows"); + } + + ResultSet generatedKeys = statement.getGeneratedKeys(); + if (generatedKeys.next()) { + Long id = generatedKeys.getObject(1, Long.class); + book.setId(id); + } + } catch (SQLException e) { + throw new DataProcessingException("Can' add a new book: " + book); + } + return book; + } + + @Override + public Optional findById(Long id) { + String sql = "SELECT * FROM books WHERE id = ?"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sql, + Statement.RETURN_GENERATED_KEYS)) { + statement.setLong(1, id); + ResultSet resultSet = statement.executeQuery(); + + if (resultSet.next()) { + return Optional.of(getBookFromResultSet(resultSet)); + } + } catch (SQLException e) { + throw new DataProcessingException("Can not create connection to the DB"); + } + return Optional.empty(); + } + + @Override + public List findAll() { + List listOfBooks = new ArrayList<>(); + String sql = "SELECT * FROM books;"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sql)) { + ResultSet resultSet = statement.executeQuery(); + + while (resultSet.next()) { + listOfBooks.add(getBookFromResultSet(resultSet)); + } + } catch (SQLException e) { + throw new DataProcessingException("Can not create connection to the DB"); + } + return listOfBooks; + } + + @Override + public Book update(Book book) { + String sql = "UPDATE books SET title = ?, price = ? WHERE id = ?"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sql)) { + statement.setString(1, book.getTitle()); + statement.setBigDecimal(2, book.getPrice()); + statement.setLong(3, book.getId()); + return book; + } catch (SQLException e) { + throw new DataProcessingException("Can't update book: " + book); + } + } + + @Override + public boolean deleteById(Long id) { + String sql = "DELETE FROM books WHERE id = ?"; + try (Connection connection = ConnectionUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(sql)) { + statement.setLong(1, id); + return statement.executeUpdate() > 0; + } catch (SQLException e) { + throw new DataProcessingException("Can't delete book"); + } + } + + private Book getBookFromResultSet(ResultSet resultSet) throws SQLException { + Long id = resultSet.getLong("id"); + String title = resultSet.getString("title"); + BigDecimal price = resultSet.getBigDecimal("price"); + return new Book(id, title, price); + } +} diff --git a/src/main/java/mate/academy/lib/Injector.java b/src/main/java/mate/academy/lib/Injector.java index ea13c49e..60085d2f 100644 --- a/src/main/java/mate/academy/lib/Injector.java +++ b/src/main/java/mate/academy/lib/Injector.java @@ -12,7 +12,7 @@ public class Injector { private static final Map injectors = new HashMap<>(); - private final List> classes = new ArrayList<>(); + private static final List> classes = new ArrayList<>(); private Injector(String mainPackageName) { try { @@ -31,12 +31,12 @@ public static Injector getInstance(String mainPackageName) { return injector; } - public Object getInstance(Class certainInterface) { + public static Object getInstance(Class certainInterface) { Class clazz = findClassExtendingInterface(certainInterface); return createInstance(clazz); } - private Class findClassExtendingInterface(Class certainInterface) { + private static Class findClassExtendingInterface(Class certainInterface) { for (Class clazz : classes) { Class[] interfaces = clazz.getInterfaces(); for (Class singleInterface : interfaces) { @@ -51,7 +51,7 @@ private Class findClassExtendingInterface(Class certainInterface) { + " interface and has valid annotation (Dao or Service)"); } - private Object createInstance(Class clazz) { + private static Object createInstance(Class clazz) { Object newInstance; try { Constructor classConstructor = clazz.getConstructor(); 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..6feb2f87 --- /dev/null +++ b/src/main/java/mate/academy/model/Book.java @@ -0,0 +1,51 @@ +package mate.academy.model; + +import java.math.BigDecimal; + +public class Book { + private Long id; + private String title; + private BigDecimal price; + + public Book() { + } + + 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/java/mate/academy/service/DataProcessingException.java b/src/main/java/mate/academy/service/DataProcessingException.java new file mode 100644 index 00000000..ea747198 --- /dev/null +++ b/src/main/java/mate/academy/service/DataProcessingException.java @@ -0,0 +1,7 @@ +package mate.academy.service; + +public class DataProcessingException extends RuntimeException { + public DataProcessingException(String message) { + super(message); + } +} diff --git a/src/main/resources/init_db.sql b/src/main/resources/init_db.sql new file mode 100644 index 00000000..b9f89bd4 --- /dev/null +++ b/src/main/resources/init_db.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS books( +id BIGINT AUTO_INCREMENT PRIMARY KEY, +title VARCHAR (255) NOT NULL, +price DECIMAL (10, 2) NOT NULL +); \ No newline at end of file From 9a41b315fb6301024a5e3a4763e97195db1a8108 Mon Sep 17 00:00:00 2001 From: Nikita Khilobok Date: Mon, 30 Sep 2024 09:31:19 +0300 Subject: [PATCH 2/3] hw is done, please check --- src/main/java/mate/academy/ConnectionUtil.java | 14 ++++++++++++-- src/main/java/mate/academy/Main.java | 2 +- .../java/mate/academy/dao/impl/BookDaoImpl.java | 16 ++++++++-------- src/main/java/mate/academy/lib/Injector.java | 2 +- src/main/resources/password.txt | 1 + 5 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 src/main/resources/password.txt diff --git a/src/main/java/mate/academy/ConnectionUtil.java b/src/main/java/mate/academy/ConnectionUtil.java index 5261f2a0..fef5e4e8 100644 --- a/src/main/java/mate/academy/ConnectionUtil.java +++ b/src/main/java/mate/academy/ConnectionUtil.java @@ -1,20 +1,30 @@ package mate.academy; +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; public class ConnectionUtil { + private static String password; private static final String DB_URL = "jdbc:mysql://localhost:3306/jdbc_intro"; private static final String USERNAME = "root"; - private static final String PASSWORD = "Nk102030!"; + private static final String PASSWORD_PATH = "src/main/resources/password.txt"; private static final Properties DB_PROPERTIES; static { + try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(PASSWORD_PATH))) { + password = bufferedReader.readLine(); + } catch (IOException e) { + throw new RuntimeException("Can't read file", e); + } DB_PROPERTIES = new Properties(); DB_PROPERTIES.put("user", USERNAME); - DB_PROPERTIES.put("password", PASSWORD); + DB_PROPERTIES.put("password", password); try { Class.forName("com.mysql.cj.jdbc.Driver"); diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java index 3fd58f5c..050d1e59 100644 --- a/src/main/java/mate/academy/Main.java +++ b/src/main/java/mate/academy/Main.java @@ -11,7 +11,7 @@ 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); + BookDao bookDao = (BookDao) injector.getDaoInstance(BookDao.class); Book book = new Book(); book.setTitle("NewTitle"); diff --git a/src/main/java/mate/academy/dao/impl/BookDaoImpl.java b/src/main/java/mate/academy/dao/impl/BookDaoImpl.java index a5c714e2..a916fc92 100644 --- a/src/main/java/mate/academy/dao/impl/BookDaoImpl.java +++ b/src/main/java/mate/academy/dao/impl/BookDaoImpl.java @@ -27,7 +27,7 @@ public Book create(Book book) { statement.setBigDecimal(2, book.getPrice()); int affectedRows = statement.executeUpdate(); - if (affectedRows < 0) { + if (affectedRows == 0) { throw new DataProcessingException("Expected to insert at least one row," + " but inserted 0 rows"); } @@ -38,7 +38,7 @@ public Book create(Book book) { book.setId(id); } } catch (SQLException e) { - throw new DataProcessingException("Can' add a new book: " + book); + throw new DataProcessingException("Can' add a new book with id: " + book.getId()); } return book; } @@ -47,8 +47,7 @@ public Book create(Book book) { public Optional findById(Long id) { String sql = "SELECT * FROM books WHERE id = ?"; try (Connection connection = ConnectionUtil.getConnection(); - PreparedStatement statement = connection.prepareStatement(sql, - Statement.RETURN_GENERATED_KEYS)) { + PreparedStatement statement = connection.prepareStatement(sql)) { statement.setLong(1, id); ResultSet resultSet = statement.executeQuery(); @@ -56,7 +55,7 @@ public Optional findById(Long id) { return Optional.of(getBookFromResultSet(resultSet)); } } catch (SQLException e) { - throw new DataProcessingException("Can not create connection to the DB"); + throw new DataProcessingException("Can't find a book with id: " + id); } return Optional.empty(); } @@ -73,7 +72,7 @@ public List findAll() { listOfBooks.add(getBookFromResultSet(resultSet)); } } catch (SQLException e) { - throw new DataProcessingException("Can not create connection to the DB"); + throw new DataProcessingException("Can't retrieve all books from the database."); } return listOfBooks; } @@ -86,9 +85,10 @@ public Book update(Book book) { statement.setString(1, book.getTitle()); statement.setBigDecimal(2, book.getPrice()); statement.setLong(3, book.getId()); + statement.executeUpdate(); return book; } catch (SQLException e) { - throw new DataProcessingException("Can't update book: " + book); + throw new DataProcessingException("Can't update the book with id: " + book.getId()); } } @@ -100,7 +100,7 @@ public boolean deleteById(Long id) { statement.setLong(1, id); return statement.executeUpdate() > 0; } catch (SQLException e) { - throw new DataProcessingException("Can't delete book"); + throw new DataProcessingException("Can't delete the book with id: " + id); } } diff --git a/src/main/java/mate/academy/lib/Injector.java b/src/main/java/mate/academy/lib/Injector.java index 60085d2f..df6e982e 100644 --- a/src/main/java/mate/academy/lib/Injector.java +++ b/src/main/java/mate/academy/lib/Injector.java @@ -31,7 +31,7 @@ public static Injector getInstance(String mainPackageName) { return injector; } - public static Object getInstance(Class certainInterface) { + public static Object getDaoInstance(Class certainInterface) { Class clazz = findClassExtendingInterface(certainInterface); return createInstance(clazz); } diff --git a/src/main/resources/password.txt b/src/main/resources/password.txt new file mode 100644 index 00000000..1b2823af --- /dev/null +++ b/src/main/resources/password.txt @@ -0,0 +1 @@ +Nk102030! \ No newline at end of file From 6677353a3997c1053f8e2171745f08d659aae5d7 Mon Sep 17 00:00:00 2001 From: Nikita Khilobok Date: Mon, 30 Sep 2024 09:36:43 +0300 Subject: [PATCH 3/3] hw is done, please check --- src/main/java/mate/academy/dao/impl/BookDaoImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/mate/academy/dao/impl/BookDaoImpl.java b/src/main/java/mate/academy/dao/impl/BookDaoImpl.java index a916fc92..121be0cd 100644 --- a/src/main/java/mate/academy/dao/impl/BookDaoImpl.java +++ b/src/main/java/mate/academy/dao/impl/BookDaoImpl.java @@ -105,7 +105,7 @@ public boolean deleteById(Long id) { } private Book getBookFromResultSet(ResultSet resultSet) throws SQLException { - Long id = resultSet.getLong("id"); + Long id = resultSet.getObject("id", Long.class); String title = resultSet.getString("title"); BigDecimal price = resultSet.getBigDecimal("price"); return new Book(id, title, price);