From 10cd16082ee9a5ef434b5b1a5e43d7c03fa8b9f8 Mon Sep 17 00:00:00 2001 From: Andrii Selivonchyk Date: Tue, 14 May 2024 20:10:40 +0300 Subject: [PATCH 1/2] Solved task jv-jdbc-intro: - implemented BookDao class with CRUD operations to retrieve needed data from DB; - created util class - ConnectionUtil to establish connection with DB; - added DbException and DataProcessingException as custom exceptions; - all application constants moved for separate Constants class; - used app.properties file for common variables; - edited init_db.sql for creating DB schema and table; - in pom.xml added necessary dependency; --- pom.xml | 8 ++ src/main/java/mate/academy/Main.java | 24 ++++ src/main/java/mate/academy/dao/BookDao.java | 17 +++ .../mate/academy/dao/impl/BookDaoImpl.java | 105 ++++++++++++++++++ src/main/java/mate/academy/entity/Book.java | 49 ++++++++ .../exception/DataProcessingException.java | 8 ++ .../mate/academy/exception/DbException.java | 8 ++ .../mate/academy/util/ConnectionUtil.java | 33 ++++++ .../java/mate/academy/util/Constants.java | 15 +++ src/main/resources/app.properties | 2 + src/main/resources/init_db.sql | 8 ++ 11 files changed, 277 insertions(+) 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/entity/Book.java create mode 100644 src/main/java/mate/academy/exception/DataProcessingException.java create mode 100644 src/main/java/mate/academy/exception/DbException.java create mode 100644 src/main/java/mate/academy/util/ConnectionUtil.java create mode 100644 src/main/java/mate/academy/util/Constants.java create mode 100644 src/main/resources/app.properties create mode 100644 src/main/resources/init_db.sql diff --git a/pom.xml b/pom.xml index 683e84ec..ee12ea36 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,14 @@ + + + mysql + mysql-connector-java + 8.0.33 + + + diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java index 0058fbf9..54396841 100644 --- a/src/main/java/mate/academy/Main.java +++ b/src/main/java/mate/academy/Main.java @@ -1,7 +1,31 @@ package mate.academy; +import java.math.BigDecimal; +import java.util.List; +import mate.academy.dao.BookDao; +import mate.academy.entity.Book; +import mate.academy.lib.Injector; + 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("Heroes Land", new BigDecimal(15)); + Book savedBook = bookDao.create(book); + System.out.println(savedBook); + + List bookList = bookDao.findAll(); + bookList.forEach(System.out::println); + + Book bookFromDB = bookDao.findById(1L).get(); + System.out.println(bookFromDB); + + bookFromDB.setPrice(new BigDecimal(25)); + Book updatedBook = bookDao.update(bookFromDB); + System.out.println(updatedBook); + boolean isDeleted = bookDao.deleteById(1L); + System.out.println(isDeleted); } } 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..d611431b --- /dev/null +++ b/src/main/java/mate/academy/dao/BookDao.java @@ -0,0 +1,17 @@ +package mate.academy.dao; + +import java.util.List; +import java.util.Optional; +import mate.academy.entity.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/impl/BookDaoImpl.java b/src/main/java/mate/academy/dao/impl/BookDaoImpl.java new file mode 100644 index 00000000..dd83feae --- /dev/null +++ b/src/main/java/mate/academy/dao/impl/BookDaoImpl.java @@ -0,0 +1,105 @@ +package mate.academy.dao.impl; + +import static mate.academy.util.Constants.GET_ALL_BOOKS_QUERY; +import static mate.academy.util.Constants.GET_BOOK_BY_ID_QUERY; +import static mate.academy.util.Constants.SAVE_BOOK_QUERY; +import static mate.academy.util.Constants.UPDATE_BOOK_QUERY; + +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.dao.BookDao; +import mate.academy.entity.Book; +import mate.academy.exception.DataProcessingException; +import mate.academy.lib.Dao; +import mate.academy.util.ConnectionUtil; + +@Dao +public class BookDaoImpl implements BookDao { + + @Override + public Book create(Book book) { + try (PreparedStatement createBookStatement = ConnectionUtil.getConnection() + .prepareStatement(SAVE_BOOK_QUERY, Statement.RETURN_GENERATED_KEYS)) { + createBookStatement.setString(1, book.getTitle()); + createBookStatement.setBigDecimal(2, book.getPrice()); + createBookStatement.executeUpdate(); + ResultSet generatedKeys = createBookStatement.getGeneratedKeys(); + if (generatedKeys.next()) { + book.setId(generatedKeys.getObject(1, Long.class)); + } + return book; + } catch (SQLException e) { + throw new DataProcessingException("Can`t add book " + book + " to DB", e); + } + } + + @Override + public Optional findById(Long id) { + try (PreparedStatement getBookByIdStatement = + ConnectionUtil.getConnection().prepareStatement(GET_BOOK_BY_ID_QUERY)) { + getBookByIdStatement.setLong(1, id); + ResultSet resultSet = getBookByIdStatement.executeQuery(); + Book book = null; + if (resultSet.next()) { + book = parseBookFromResultSet(resultSet); + } + return Optional.ofNullable(book); + } catch (SQLException e) { + throw new DataProcessingException("Can't get book by id: " + id + " from DB", e); + } + } + + @Override + public List findAll() { + List books = new ArrayList<>(); + try (PreparedStatement getAllBooksStatement = + ConnectionUtil.getConnection().prepareStatement(GET_ALL_BOOKS_QUERY)) { + ResultSet resultSet = getAllBooksStatement.executeQuery(); + while (resultSet.next()) { + books.add(parseBookFromResultSet(resultSet)); + } + return books; + } catch (SQLException e) { + throw new DataProcessingException("Can't get books from DB", e); + } + } + + @Override + public Book update(Book book) { + try (PreparedStatement upadateBookStatment = + ConnectionUtil.getConnection().prepareStatement( + UPDATE_BOOK_QUERY, Statement.RETURN_GENERATED_KEYS)) { + upadateBookStatment.setString(1, book.getTitle()); + upadateBookStatment.setBigDecimal(2, book.getPrice()); + upadateBookStatment.setLong(3, book.getId()); + upadateBookStatment.executeUpdate(); + return book; + } catch (SQLException e) { + throw new DataProcessingException("Can't update book: " + book + " in DB", e); + } + } + + @Override + public boolean deleteById(Long id) { + try (PreparedStatement statement = ConnectionUtil.getConnection().prepareStatement( + "DELETE FROM books WHERE id=?", Statement.RETURN_GENERATED_KEYS)) { + statement.setLong(1, id); + return statement.executeUpdate() > 0; + } catch (SQLException e) { + throw new DataProcessingException("Can't delete book by id: " + id + " from DB", e); + } + } + + private Book parseBookFromResultSet(ResultSet resultSet) throws SQLException { + return new Book( + resultSet.getLong("id"), + resultSet.getString("title"), + resultSet.getBigDecimal("price") + ); + } +} diff --git a/src/main/java/mate/academy/entity/Book.java b/src/main/java/mate/academy/entity/Book.java new file mode 100644 index 00000000..4cfa7431 --- /dev/null +++ b/src/main/java/mate/academy/entity/Book.java @@ -0,0 +1,49 @@ +package mate.academy.entity; + +import java.math.BigDecimal; + +public class Book { + private long id; + private String title; + private BigDecimal price; + + public Book(long id, String title, BigDecimal price) { + this.id = id; + this.title = title; + this.price = price; + } + + public Book(String title, BigDecimal price) { + 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 String.format("Book: {id: %d title - %s, price - %s}", id, title, price); + } +} 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..dd597270 --- /dev/null +++ b/src/main/java/mate/academy/exception/DataProcessingException.java @@ -0,0 +1,8 @@ +package mate.academy.exception; + +public class DataProcessingException extends RuntimeException { + + public DataProcessingException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/mate/academy/exception/DbException.java b/src/main/java/mate/academy/exception/DbException.java new file mode 100644 index 00000000..f41a981d --- /dev/null +++ b/src/main/java/mate/academy/exception/DbException.java @@ -0,0 +1,8 @@ +package mate.academy.exception; + +public class DbException extends RuntimeException { + + public DbException(String message) { + super(message); + } +} diff --git a/src/main/java/mate/academy/util/ConnectionUtil.java b/src/main/java/mate/academy/util/ConnectionUtil.java new file mode 100644 index 00000000..a0463c9e --- /dev/null +++ b/src/main/java/mate/academy/util/ConnectionUtil.java @@ -0,0 +1,33 @@ +package mate.academy.util; + +import java.io.FileInputStream; +import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; +import mate.academy.exception.DbException; + +public class ConnectionUtil { + private static final Properties dbProperties = new Properties(); + + static { + try { + dbProperties.load(new FileInputStream(Constants.APP_PROPERTIES_FILE)); + Class.forName(dbProperties.getProperty(Constants.DB_DRIVER_TAG)); + } catch (IOException e) { + throw new DbException("Can`t load JDBC driver for MYSQL: " + e.getMessage()); + } catch (ClassNotFoundException e) { + throw new DbException("Can`t load driver properties: " + e.getMessage()); + } + } + + public static Connection getConnection() { + try { + return DriverManager.getConnection( + dbProperties.getProperty(Constants.DB_URL_TAG)); + } catch (SQLException e) { + throw new DbException("Can`t create connection for DB: " + e.getMessage()); + } + } +} diff --git a/src/main/java/mate/academy/util/Constants.java b/src/main/java/mate/academy/util/Constants.java new file mode 100644 index 00000000..10affe1e --- /dev/null +++ b/src/main/java/mate/academy/util/Constants.java @@ -0,0 +1,15 @@ +package mate.academy.util; + +public class Constants { + // Application paths + public static final String APP_PROPERTIES_FILE = "src/main/resources/app.properties"; + // DB connection constants + public static final String DB_DRIVER_TAG = "db.driver"; + public static final String DB_URL_TAG = "db.connection.url"; + // Book dao sql query + public static final String SAVE_BOOK_QUERY = "INSERT INTO books(title, price) VALUES(?, ?)"; + public static final String GET_BOOK_BY_ID_QUERY = "SELECT * FROM books WHERE id = ?"; + public static final String GET_ALL_BOOKS_QUERY = "SELECT * FROM books"; + public static final String UPDATE_BOOK_QUERY = + "UPDATE books SET title = ?, price = ? WHERE id = ?"; +} diff --git a/src/main/resources/app.properties b/src/main/resources/app.properties new file mode 100644 index 00000000..34666141 --- /dev/null +++ b/src/main/resources/app.properties @@ -0,0 +1,2 @@ +db.driver=com.mysql.cj.jdbc.Driver +db.connection.url=jdbc:mysql://localhost:3306/testdb?user=root&password=root diff --git a/src/main/resources/init_db.sql b/src/main/resources/init_db.sql new file mode 100644 index 00000000..ff778a94 --- /dev/null +++ b/src/main/resources/init_db.sql @@ -0,0 +1,8 @@ +CREATE SCHEMA IF NOT EXISTS testdb DEFAULT CHARACTER SET utf8; +USE testdb; + +CREATE TABLE IF NOT EXISTS books ( + id bigint AUTO_INCREMENT PRIMARY KEY, + title varchar(45) NOT NULL, + price decimal DEFAULT 0, +); From 1ebd470dbf679c196ac4389d60c63cb9fbe44ad2 Mon Sep 17 00:00:00 2001 From: Andrii Selivonchyk Date: Wed, 15 May 2024 15:39:02 +0300 Subject: [PATCH 2/2] Code style changes. --- .../mate/academy/exception/DataProcessingException.java | 1 - src/main/java/mate/academy/exception/DbException.java | 1 - src/main/java/mate/academy/util/ConnectionUtil.java | 8 ++++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/mate/academy/exception/DataProcessingException.java b/src/main/java/mate/academy/exception/DataProcessingException.java index dd597270..63b937dc 100644 --- a/src/main/java/mate/academy/exception/DataProcessingException.java +++ b/src/main/java/mate/academy/exception/DataProcessingException.java @@ -1,7 +1,6 @@ package mate.academy.exception; public class DataProcessingException extends RuntimeException { - public DataProcessingException(String message, Throwable cause) { super(message, cause); } diff --git a/src/main/java/mate/academy/exception/DbException.java b/src/main/java/mate/academy/exception/DbException.java index f41a981d..04ebb6b8 100644 --- a/src/main/java/mate/academy/exception/DbException.java +++ b/src/main/java/mate/academy/exception/DbException.java @@ -1,7 +1,6 @@ package mate.academy.exception; public class DbException extends RuntimeException { - public DbException(String message) { super(message); } diff --git a/src/main/java/mate/academy/util/ConnectionUtil.java b/src/main/java/mate/academy/util/ConnectionUtil.java index a0463c9e..156693eb 100644 --- a/src/main/java/mate/academy/util/ConnectionUtil.java +++ b/src/main/java/mate/academy/util/ConnectionUtil.java @@ -9,12 +9,12 @@ import mate.academy.exception.DbException; public class ConnectionUtil { - private static final Properties dbProperties = new Properties(); + private static final Properties DB_PROPERTIES = new Properties(); static { try { - dbProperties.load(new FileInputStream(Constants.APP_PROPERTIES_FILE)); - Class.forName(dbProperties.getProperty(Constants.DB_DRIVER_TAG)); + DB_PROPERTIES.load(new FileInputStream(Constants.APP_PROPERTIES_FILE)); + Class.forName(DB_PROPERTIES.getProperty(Constants.DB_DRIVER_TAG)); } catch (IOException e) { throw new DbException("Can`t load JDBC driver for MYSQL: " + e.getMessage()); } catch (ClassNotFoundException e) { @@ -25,7 +25,7 @@ public class ConnectionUtil { public static Connection getConnection() { try { return DriverManager.getConnection( - dbProperties.getProperty(Constants.DB_URL_TAG)); + DB_PROPERTIES.getProperty(Constants.DB_URL_TAG)); } catch (SQLException e) { throw new DbException("Can`t create connection for DB: " + e.getMessage()); }