372 lines
15 KiB
Java
372 lines
15 KiB
Java
package com.mzh.library.controller;
|
|
|
|
import com.mzh.library.dao.impl.JdbcBookDao;
|
|
import com.mzh.library.entity.AuthenticatedUser;
|
|
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.service.BookService;
|
|
import com.mzh.library.service.ServiceResult;
|
|
import com.mzh.library.service.impl.BookServiceImpl;
|
|
import com.mzh.library.util.SessionAttributes;
|
|
|
|
import java.io.IOException;
|
|
import java.util.Collections;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
|
|
import javax.servlet.ServletException;
|
|
import javax.servlet.http.HttpServlet;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
import javax.servlet.http.HttpSession;
|
|
|
|
public class BookManagementServlet extends HttpServlet {
|
|
private static final String MANAGE_JSP = "/WEB-INF/jsp/books/manage.jsp";
|
|
private static final String FORM_JSP = "/WEB-INF/jsp/books/form.jsp";
|
|
private static final String UNAUTHORIZED_JSP = "/WEB-INF/jsp/auth/unauthorized.jsp";
|
|
private static final String FLASH_SUCCESS = "flashSuccess";
|
|
private static final String FLASH_ERROR = "flashError";
|
|
|
|
private BookService bookService;
|
|
|
|
@Override
|
|
public void init() {
|
|
this.bookService = new BookServiceImpl(new JdbcBookDao());
|
|
}
|
|
|
|
@Override
|
|
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
|
String path = request.getServletPath();
|
|
if ("/books/new".equals(path)) {
|
|
renderForm(request, response, "Create book", "/books", new Book(), Collections.emptyMap(),
|
|
Collections.emptyMap(), null);
|
|
return;
|
|
}
|
|
if ("/books/edit".equals(path)) {
|
|
showEditForm(request, response);
|
|
return;
|
|
}
|
|
if (!"/books".equals(path)) {
|
|
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
|
return;
|
|
}
|
|
|
|
showManagementList(request, response);
|
|
}
|
|
|
|
@Override
|
|
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
|
String path = request.getServletPath();
|
|
if ("/books".equals(path)) {
|
|
createBook(request, response);
|
|
return;
|
|
}
|
|
if ("/books/update".equals(path)) {
|
|
updateBook(request, response);
|
|
return;
|
|
}
|
|
if ("/books/delete".equals(path)) {
|
|
deleteBook(request, response);
|
|
return;
|
|
}
|
|
|
|
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
|
}
|
|
|
|
private void showManagementList(HttpServletRequest request, HttpServletResponse response)
|
|
throws ServletException, IOException {
|
|
BookSearchCriteria criteria = searchCriteria(request);
|
|
request.setAttribute("criteria", criteria);
|
|
applyFlash(request);
|
|
|
|
ServiceResult<List<BookCategory>> categoryResult = bookService.listCategories();
|
|
request.setAttribute("categories", categoryResult.isSuccessful()
|
|
? categoryResult.getData()
|
|
: Collections.emptyList());
|
|
if (!categoryResult.isSuccessful()) {
|
|
request.setAttribute("errorMessage", categoryResult.getMessage());
|
|
}
|
|
|
|
ServiceResult<List<Book>> searchResult = bookService.searchBooks(criteria);
|
|
request.setAttribute("books", searchResult.isSuccessful()
|
|
? searchResult.getData()
|
|
: Collections.emptyList());
|
|
if (!searchResult.isSuccessful()) {
|
|
request.setAttribute("errorMessage", searchResult.getMessage());
|
|
request.setAttribute("errors", searchResult.getErrors());
|
|
}
|
|
|
|
request.getRequestDispatcher(MANAGE_JSP).forward(request, response);
|
|
}
|
|
|
|
private void showEditForm(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
|
long id = requiredLong(request.getParameter("id"), -1L);
|
|
ServiceResult<Optional<Book>> result = bookService.findBook(id);
|
|
if (!result.isSuccessful() || !result.getData().isPresent()) {
|
|
flashError(request, result.isSuccessful() ? "Book was not found." : result.getMessage());
|
|
response.sendRedirect(request.getContextPath() + "/books");
|
|
return;
|
|
}
|
|
|
|
renderForm(request, response, "Edit book", "/books/update", result.getData().get(),
|
|
Collections.emptyMap(), Collections.emptyMap(), null);
|
|
}
|
|
|
|
private void createBook(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
|
BookForm form = readBookForm(request, false);
|
|
if (!form.getErrors().isEmpty()) {
|
|
renderForm(request, response, "Create book", "/books", form.getBook(), form.getValues(),
|
|
form.getErrors(), "Please correct the highlighted book fields.");
|
|
return;
|
|
}
|
|
|
|
ServiceResult<Long> result = bookService.createBook(currentUser(request), form.getBook());
|
|
if (!result.isSuccessful()) {
|
|
handleFormFailure(request, response, "Create book", "/books", form, result);
|
|
return;
|
|
}
|
|
|
|
flashSuccess(request, result.getMessage());
|
|
response.sendRedirect(request.getContextPath() + "/books");
|
|
}
|
|
|
|
private void updateBook(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
|
BookForm form = readBookForm(request, true);
|
|
if (!form.getErrors().isEmpty()) {
|
|
renderForm(request, response, "Edit book", "/books/update", form.getBook(), form.getValues(),
|
|
form.getErrors(), "Please correct the highlighted book fields.");
|
|
return;
|
|
}
|
|
|
|
ServiceResult<Void> result = bookService.updateBook(currentUser(request), form.getBook());
|
|
if (!result.isSuccessful()) {
|
|
handleFormFailure(request, response, "Edit book", "/books/update", form, result);
|
|
return;
|
|
}
|
|
|
|
flashSuccess(request, result.getMessage());
|
|
response.sendRedirect(request.getContextPath() + "/books");
|
|
}
|
|
|
|
private void deleteBook(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
|
long id = requiredLong(request.getParameter("id"), -1L);
|
|
ServiceResult<Void> result = bookService.deleteBook(currentUser(request), id);
|
|
if (isPermissionDenied(result)) {
|
|
forwardDenied(request, response, result.getMessage());
|
|
return;
|
|
}
|
|
if (result.isSuccessful()) {
|
|
flashSuccess(request, result.getMessage());
|
|
} else {
|
|
flashError(request, result.getMessage());
|
|
}
|
|
response.sendRedirect(request.getContextPath() + "/books");
|
|
}
|
|
|
|
private void handleFormFailure(HttpServletRequest request, HttpServletResponse response, String title,
|
|
String action, BookForm form, ServiceResult<?> result)
|
|
throws ServletException, IOException {
|
|
if (isPermissionDenied(result)) {
|
|
forwardDenied(request, response, result.getMessage());
|
|
return;
|
|
}
|
|
renderForm(request, response, title, action, form.getBook(), form.getValues(), result.getErrors(),
|
|
result.getMessage());
|
|
}
|
|
|
|
private void renderForm(HttpServletRequest request, HttpServletResponse response, String title, String action,
|
|
Book book, Map<String, String> formValues, Map<String, String> errors, String errorMessage)
|
|
throws ServletException, IOException {
|
|
ServiceResult<List<BookCategory>> categoryResult = bookService.listCategories();
|
|
request.setAttribute("categories", categoryResult.isSuccessful()
|
|
? categoryResult.getData()
|
|
: Collections.emptyList());
|
|
request.setAttribute("statuses", BookStatus.values());
|
|
request.setAttribute("formTitle", title);
|
|
request.setAttribute("formAction", action);
|
|
request.setAttribute("book", book);
|
|
request.setAttribute("formValues", formValues);
|
|
request.setAttribute("errors", errors);
|
|
if (errorMessage != null && !errorMessage.isEmpty()) {
|
|
request.setAttribute("errorMessage", errorMessage);
|
|
} else if (!categoryResult.isSuccessful()) {
|
|
request.setAttribute("errorMessage", categoryResult.getMessage());
|
|
}
|
|
request.getRequestDispatcher(FORM_JSP).forward(request, response);
|
|
}
|
|
|
|
private BookForm readBookForm(HttpServletRequest request, boolean requireId) {
|
|
Map<String, String> values = formValues(request);
|
|
Map<String, String> errors = new LinkedHashMap<>();
|
|
Book book = new Book();
|
|
|
|
if (requireId) {
|
|
book.setId(parseLong(values.get("id"), "id", "Select a valid book.", errors));
|
|
}
|
|
book.setIdentifier(values.get("identifier"));
|
|
book.setTitle(values.get("title"));
|
|
book.setAuthor(values.get("author"));
|
|
book.setCategoryId(parseLong(values.get("categoryId"), "categoryId", "Select a category.", errors));
|
|
book.setTotalCopies(parseInt(values.get("totalCopies"), "totalCopies", "Enter a valid total copy count.", errors));
|
|
book.setAvailableCopies(parseInt(values.get("availableCopies"), "availableCopies",
|
|
"Enter a valid available copy count.", errors));
|
|
|
|
try {
|
|
book.setStatus(BookStatus.fromCode(values.get("status")));
|
|
} catch (IllegalArgumentException ex) {
|
|
errors.put("status", "Select a status.");
|
|
}
|
|
|
|
return new BookForm(book, values, errors);
|
|
}
|
|
|
|
private Map<String, String> formValues(HttpServletRequest request) {
|
|
Map<String, String> values = new LinkedHashMap<>();
|
|
values.put("id", trim(request.getParameter("id")));
|
|
values.put("identifier", trim(request.getParameter("identifier")));
|
|
values.put("title", trim(request.getParameter("title")));
|
|
values.put("author", trim(request.getParameter("author")));
|
|
values.put("categoryId", trim(request.getParameter("categoryId")));
|
|
values.put("totalCopies", trim(request.getParameter("totalCopies")));
|
|
values.put("availableCopies", trim(request.getParameter("availableCopies")));
|
|
values.put("status", trim(request.getParameter("status")));
|
|
return values;
|
|
}
|
|
|
|
private BookSearchCriteria searchCriteria(HttpServletRequest request) {
|
|
return new BookSearchCriteria(
|
|
request.getParameter("identifier"),
|
|
request.getParameter("title"),
|
|
request.getParameter("author"),
|
|
optionalLong(request.getParameter("categoryId"))
|
|
);
|
|
}
|
|
|
|
private Long optionalLong(String value) {
|
|
String trimmed = trim(value);
|
|
if (trimmed.isEmpty()) {
|
|
return null;
|
|
}
|
|
try {
|
|
return Long.valueOf(trimmed);
|
|
} catch (NumberFormatException ex) {
|
|
return -1L;
|
|
}
|
|
}
|
|
|
|
private long parseLong(String value, String field, String message, Map<String, String> errors) {
|
|
String trimmed = trim(value);
|
|
if (trimmed.isEmpty()) {
|
|
errors.put(field, message);
|
|
return 0L;
|
|
}
|
|
try {
|
|
long parsed = Long.parseLong(trimmed);
|
|
if (parsed <= 0) {
|
|
errors.put(field, message);
|
|
}
|
|
return parsed;
|
|
} catch (NumberFormatException ex) {
|
|
errors.put(field, message);
|
|
return 0L;
|
|
}
|
|
}
|
|
|
|
private int parseInt(String value, String field, String message, Map<String, String> errors) {
|
|
String trimmed = trim(value);
|
|
if (trimmed.isEmpty()) {
|
|
errors.put(field, message);
|
|
return -1;
|
|
}
|
|
try {
|
|
return Integer.parseInt(trimmed);
|
|
} catch (NumberFormatException ex) {
|
|
errors.put(field, message);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
private long requiredLong(String value, long fallback) {
|
|
try {
|
|
long parsed = Long.parseLong(trim(value));
|
|
return parsed > 0 ? parsed : fallback;
|
|
} catch (NumberFormatException ex) {
|
|
return fallback;
|
|
}
|
|
}
|
|
|
|
private boolean isPermissionDenied(ServiceResult<?> result) {
|
|
return !result.isSuccessful() && "You do not have permission to manage books.".equals(result.getMessage());
|
|
}
|
|
|
|
private void forwardDenied(HttpServletRequest request, HttpServletResponse response, String message)
|
|
throws ServletException, IOException {
|
|
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
|
request.setAttribute("errorMessage", message);
|
|
request.getRequestDispatcher(UNAUTHORIZED_JSP).forward(request, response);
|
|
}
|
|
|
|
private AuthenticatedUser currentUser(HttpServletRequest request) {
|
|
HttpSession session = request.getSession(false);
|
|
Object value = session == null ? null : session.getAttribute(SessionAttributes.AUTHENTICATED_USER);
|
|
return value instanceof AuthenticatedUser ? (AuthenticatedUser) value : null;
|
|
}
|
|
|
|
private void applyFlash(HttpServletRequest request) {
|
|
HttpSession session = request.getSession(false);
|
|
if (session == null) {
|
|
return;
|
|
}
|
|
moveFlash(session, request, FLASH_SUCCESS, "successMessage");
|
|
moveFlash(session, request, FLASH_ERROR, "errorMessage");
|
|
}
|
|
|
|
private void moveFlash(HttpSession session, HttpServletRequest request, String sessionKey, String requestKey) {
|
|
Object value = session.getAttribute(sessionKey);
|
|
if (value != null) {
|
|
request.setAttribute(requestKey, value);
|
|
session.removeAttribute(sessionKey);
|
|
}
|
|
}
|
|
|
|
private void flashSuccess(HttpServletRequest request, String message) {
|
|
request.getSession().setAttribute(FLASH_SUCCESS, message);
|
|
}
|
|
|
|
private void flashError(HttpServletRequest request, String message) {
|
|
request.getSession().setAttribute(FLASH_ERROR, message);
|
|
}
|
|
|
|
private String trim(String value) {
|
|
return value == null ? "" : value.trim();
|
|
}
|
|
|
|
private static final class BookForm {
|
|
private final Book book;
|
|
private final Map<String, String> values;
|
|
private final Map<String, String> errors;
|
|
|
|
private BookForm(Book book, Map<String, String> values, Map<String, String> errors) {
|
|
this.book = book;
|
|
this.values = values;
|
|
this.errors = errors;
|
|
}
|
|
|
|
private Book getBook() {
|
|
return book;
|
|
}
|
|
|
|
private Map<String, String> getValues() {
|
|
return values;
|
|
}
|
|
|
|
private Map<String, String> getErrors() {
|
|
return errors;
|
|
}
|
|
}
|
|
}
|