维护入口

This commit is contained in:
Zzzz
2026-04-27 23:38:19 +08:00
parent 4155d5b1ea
commit 63738f108a
21 changed files with 1009 additions and 8 deletions
@@ -23,6 +23,7 @@ public class BookServiceImpl implements BookService {
private static final String UNAVAILABLE_MESSAGE =
"Book service is temporarily unavailable. Please try again later.";
private static final String VALIDATION_MESSAGE = "Please correct the highlighted book fields.";
private static final String CATEGORY_VALIDATION_MESSAGE = "Please correct the highlighted category fields.";
private static final String DENIED_MESSAGE = "You do not have permission to manage books.";
private final BookDao bookDao;
@@ -47,6 +48,111 @@ public class BookServiceImpl implements BookService {
}
}
@Override
public ServiceResult<Optional<BookCategory>> findCategory(long id) {
if (id <= 0) {
return ServiceResult.failure("Select a valid category.");
}
try {
return ServiceResult.success(bookDao.findCategoryById(id));
} catch (DaoException ex) {
LOGGER.log(Level.SEVERE, "Unable to load book category id=" + id, ex);
return ServiceResult.failure(UNAVAILABLE_MESSAGE);
}
}
@Override
public ServiceResult<Long> createCategory(AuthenticatedUser actor, BookCategory category) {
if (!canManageBooks(actor)) {
return ServiceResult.failure(DENIED_MESSAGE);
}
normalize(category);
Map<String, String> errors = validate(category, false);
if (!errors.isEmpty()) {
return ServiceResult.validationFailure(CATEGORY_VALIDATION_MESSAGE, errors);
}
try {
if (bookDao.findCategoryByName(category.getName()).isPresent()) {
errors.put("name", "Category name is already in use.");
return ServiceResult.validationFailure(CATEGORY_VALIDATION_MESSAGE, errors);
}
long id = bookDao.createCategory(category);
LOGGER.info("Created book category id=" + id + " actorId=" + actor.getId());
return ServiceResult.success(id, "Category created.");
} catch (DaoException ex) {
LOGGER.log(Level.SEVERE, "Unable to create book category actorId=" + actor.getId()
+ " name=" + safeCategoryName(category), ex);
return ServiceResult.failure(UNAVAILABLE_MESSAGE);
}
}
@Override
public ServiceResult<Void> updateCategory(AuthenticatedUser actor, BookCategory category) {
if (!canManageBooks(actor)) {
return ServiceResult.failure(DENIED_MESSAGE);
}
normalize(category);
Map<String, String> errors = validate(category, true);
if (!errors.isEmpty()) {
return ServiceResult.validationFailure(CATEGORY_VALIDATION_MESSAGE, errors);
}
try {
Optional<BookCategory> existingWithName = bookDao.findCategoryByName(category.getName());
if (existingWithName.isPresent() && existingWithName.get().getId() != category.getId()) {
errors.put("name", "Category name is already in use.");
return ServiceResult.validationFailure(CATEGORY_VALIDATION_MESSAGE, errors);
}
if (!bookDao.updateCategory(category)) {
return ServiceResult.failure("Category was not found.");
}
LOGGER.info("Updated book category id=" + category.getId() + " actorId=" + actor.getId());
return ServiceResult.success(null, "Category updated.");
} catch (DaoException ex) {
LOGGER.log(Level.SEVERE, "Unable to update book category id=" + category.getId()
+ " actorId=" + actor.getId(), ex);
return ServiceResult.failure(UNAVAILABLE_MESSAGE);
}
}
@Override
public ServiceResult<Void> deleteCategory(AuthenticatedUser actor, long id) {
if (!canManageBooks(actor)) {
return ServiceResult.failure(DENIED_MESSAGE);
}
if (id <= 0) {
return ServiceResult.failure("Select a valid category.");
}
try {
if (!bookDao.findCategoryById(id).isPresent()) {
return ServiceResult.failure("Category was not found.");
}
if (bookDao.countBooksByCategoryId(id) > 0) {
Map<String, String> errors = new LinkedHashMap<>();
errors.put("category", "Category is used by existing books and cannot be deleted.");
return ServiceResult.validationFailure("Category is used by existing books and cannot be deleted.",
errors);
}
if (!bookDao.deleteCategory(id)) {
return ServiceResult.failure("Category was not found.");
}
LOGGER.info("Deleted book category id=" + id + " actorId=" + actor.getId());
return ServiceResult.success(null, "Category deleted.");
} catch (DaoException ex) {
LOGGER.log(Level.SEVERE, "Unable to delete book category id=" + id + " actorId=" + actor.getId(), ex);
return ServiceResult.failure(UNAVAILABLE_MESSAGE);
}
}
@Override
public ServiceResult<List<Book>> searchBooks(BookSearchCriteria criteria) {
BookSearchCriteria normalized = criteria == null ? new BookSearchCriteria() : criteria;
@@ -171,6 +277,14 @@ public class BookServiceImpl implements BookService {
book.setAuthor(trim(book.getAuthor()));
}
private void normalize(BookCategory category) {
if (category == null) {
return;
}
category.setName(trim(category.getName()));
category.setDescription(trim(category.getDescription()));
}
private Map<String, String> validate(Book book, boolean requireId) {
Map<String, String> errors = new LinkedHashMap<>();
if (book == null) {
@@ -202,6 +316,27 @@ public class BookServiceImpl implements BookService {
return errors;
}
private Map<String, String> validate(BookCategory category, boolean requireId) {
Map<String, String> errors = new LinkedHashMap<>();
if (category == null) {
errors.put("category", "Category details are required.");
return errors;
}
if (requireId && category.getId() <= 0) {
errors.put("id", "Select a valid category.");
}
requireLength(errors, "name", category.getName(), "Category name", 96);
if (category.getDescription() != null && category.getDescription().length() > 255) {
errors.put("description", "Description must be 255 characters or fewer.");
}
return errors;
}
private String safeCategoryName(BookCategory category) {
return category == null ? "" : category.getName();
}
private void requireLength(Map<String, String> errors, String field, String value, String label, int maxLength) {
if (value == null || value.isEmpty()) {
errors.put(field, label + " is required.");