新增书籍表、列表/搜索、管理员/馆员维护入口

This commit is contained in:
Zzzz
2026-04-27 19:49:14 +08:00
parent 8777efa21d
commit 763830f767
28 changed files with 2392 additions and 8 deletions
@@ -0,0 +1,224 @@
package com.mzh.library.dao.impl;
import com.mzh.library.dao.BookDao;
import com.mzh.library.entity.Book;
import com.mzh.library.entity.BookCategory;
import com.mzh.library.entity.BookSearchCriteria;
import com.mzh.library.entity.BookStatus;
import com.mzh.library.exception.DaoException;
import com.mzh.library.util.JdbcUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class JdbcBookDao implements BookDao {
private static final String BOOK_COLUMNS = ""
+ "b.id, b.book_identifier, b.title, b.author, b.category_id, c.name AS category_name, "
+ "b.total_copies, b.available_copies, b.status, b.created_at, b.updated_at ";
private static final String BOOK_FROM = ""
+ "FROM books b "
+ "JOIN book_categories c ON c.id = b.category_id ";
private static final String FIND_ALL_CATEGORIES = ""
+ "SELECT id, name, description "
+ "FROM book_categories "
+ "ORDER BY name";
private static final String FIND_BY_ID = "SELECT " + BOOK_COLUMNS + BOOK_FROM + "WHERE b.id = ?";
private static final String FIND_BY_IDENTIFIER = "SELECT " + BOOK_COLUMNS + BOOK_FROM
+ "WHERE b.book_identifier = ?";
private static final String CREATE = ""
+ "INSERT INTO books "
+ "(book_identifier, title, author, category_id, total_copies, available_copies, status) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?)";
private static final String UPDATE = ""
+ "UPDATE books "
+ "SET book_identifier = ?, title = ?, author = ?, category_id = ?, total_copies = ?, "
+ "available_copies = ?, status = ? "
+ "WHERE id = ?";
private static final String DELETE = "DELETE FROM books WHERE id = ?";
@Override
public List<BookCategory> findAllCategories() {
try (Connection connection = JdbcUtil.getConnection();
PreparedStatement statement = connection.prepareStatement(FIND_ALL_CATEGORIES);
ResultSet resultSet = statement.executeQuery()) {
List<BookCategory> categories = new ArrayList<>();
while (resultSet.next()) {
categories.add(mapCategory(resultSet));
}
return categories;
} catch (SQLException ex) {
throw new DaoException("Unable to load book categories", ex);
}
}
@Override
public List<Book> search(BookSearchCriteria criteria) {
List<Object> parameters = new ArrayList<>();
StringBuilder sql = new StringBuilder("SELECT ")
.append(BOOK_COLUMNS)
.append(BOOK_FROM)
.append("WHERE 1 = 1 ");
appendLike(sql, parameters, "b.book_identifier", criteria.getIdentifier());
appendLike(sql, parameters, "b.title", criteria.getTitle());
appendLike(sql, parameters, "b.author", criteria.getAuthor());
if (criteria.getCategoryId() != null) {
sql.append("AND b.category_id = ? ");
parameters.add(criteria.getCategoryId());
}
sql.append("ORDER BY b.title, b.author, b.book_identifier");
try (Connection connection = JdbcUtil.getConnection();
PreparedStatement statement = connection.prepareStatement(sql.toString())) {
bind(statement, parameters);
try (ResultSet resultSet = statement.executeQuery()) {
List<Book> books = new ArrayList<>();
while (resultSet.next()) {
books.add(mapBook(resultSet));
}
return books;
}
} catch (SQLException | IllegalArgumentException ex) {
throw new DaoException("Unable to search books", ex);
}
}
@Override
public Optional<Book> findById(long id) {
try (Connection connection = JdbcUtil.getConnection();
PreparedStatement statement = connection.prepareStatement(FIND_BY_ID)) {
statement.setLong(1, id);
try (ResultSet resultSet = statement.executeQuery()) {
return resultSet.next() ? Optional.of(mapBook(resultSet)) : Optional.empty();
}
} catch (SQLException | IllegalArgumentException ex) {
throw new DaoException("Unable to load book by id", ex);
}
}
@Override
public Optional<Book> findByIdentifier(String identifier) {
try (Connection connection = JdbcUtil.getConnection();
PreparedStatement statement = connection.prepareStatement(FIND_BY_IDENTIFIER)) {
statement.setString(1, identifier);
try (ResultSet resultSet = statement.executeQuery()) {
return resultSet.next() ? Optional.of(mapBook(resultSet)) : Optional.empty();
}
} catch (SQLException | IllegalArgumentException ex) {
throw new DaoException("Unable to load book by identifier", ex);
}
}
@Override
public long create(Book book) {
try (Connection connection = JdbcUtil.getConnection();
PreparedStatement statement = connection.prepareStatement(CREATE, Statement.RETURN_GENERATED_KEYS)) {
bindBook(statement, book);
statement.executeUpdate();
try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
if (generatedKeys.next()) {
return generatedKeys.getLong(1);
}
}
throw new DaoException("Unable to read generated book id", null);
} catch (SQLException ex) {
throw new DaoException("Unable to create book", ex);
}
}
@Override
public boolean update(Book book) {
try (Connection connection = JdbcUtil.getConnection();
PreparedStatement statement = connection.prepareStatement(UPDATE)) {
bindBook(statement, book);
statement.setLong(8, book.getId());
return statement.executeUpdate() == 1;
} catch (SQLException ex) {
throw new DaoException("Unable to update book", ex);
}
}
@Override
public boolean delete(long id) {
try (Connection connection = JdbcUtil.getConnection();
PreparedStatement statement = connection.prepareStatement(DELETE)) {
statement.setLong(1, id);
return statement.executeUpdate() == 1;
} catch (SQLException ex) {
throw new DaoException("Unable to delete book", ex);
}
}
private void appendLike(StringBuilder sql, List<Object> parameters, String column, String value) {
if (value == null || value.trim().isEmpty()) {
return;
}
sql.append("AND ").append(column).append(" LIKE ? ");
parameters.add("%" + value.trim() + "%");
}
private void bind(PreparedStatement statement, List<Object> parameters) throws SQLException {
for (int i = 0; i < parameters.size(); i++) {
Object value = parameters.get(i);
if (value instanceof Long) {
statement.setLong(i + 1, (Long) value);
} else {
statement.setString(i + 1, value.toString());
}
}
}
private void bindBook(PreparedStatement statement, Book book) throws SQLException {
statement.setString(1, book.getIdentifier());
statement.setString(2, book.getTitle());
statement.setString(3, book.getAuthor());
statement.setLong(4, book.getCategoryId());
statement.setInt(5, book.getTotalCopies());
statement.setInt(6, book.getAvailableCopies());
statement.setString(7, book.getStatus().getCode());
}
private Book mapBook(ResultSet resultSet) throws SQLException {
Book book = new Book();
book.setId(resultSet.getLong("id"));
book.setIdentifier(resultSet.getString("book_identifier"));
book.setTitle(resultSet.getString("title"));
book.setAuthor(resultSet.getString("author"));
book.setCategoryId(resultSet.getLong("category_id"));
book.setCategoryName(resultSet.getString("category_name"));
book.setTotalCopies(resultSet.getInt("total_copies"));
book.setAvailableCopies(resultSet.getInt("available_copies"));
book.setStatus(BookStatus.fromCode(resultSet.getString("status")));
book.setCreatedAt(toLocalDateTime(resultSet.getTimestamp("created_at")));
book.setUpdatedAt(toLocalDateTime(resultSet.getTimestamp("updated_at")));
return book;
}
private BookCategory mapCategory(ResultSet resultSet) throws SQLException {
BookCategory category = new BookCategory();
category.setId(resultSet.getLong("id"));
category.setName(resultSet.getString("name"));
category.setDescription(resultSet.getString("description"));
return category;
}
private LocalDateTime toLocalDateTime(Timestamp timestamp) {
return timestamp == null ? null : timestamp.toLocalDateTime();
}
}