Я разрабатываю веб-страницу, используя Java сервлеты и JSP. У меня есть функционал, где в зависимости от полученного действия (действия) выполняются разные операции. Однако я столкнулся с проблемой с определенным действием (действие4), которое должно создать PDF-файл, а затем перенаправить пользователя на другую страницу.
Вопросы:
Я ценю любую помощь или предложения, которые вы можете предложить. Заранее спасибо!
Ниже приведена моя структура и проблема, с которой я столкнулся.
Сервлет:
if (action != null) {
switch (action) {
case "action1": // Add items to cart
if (carritoSQL.existeProducto(producto)) {
handleAddButton(request, response, producto, cantidad, carrito);
}
break;
case "action2": // Development-focused case
handleClearButton(request, response, session);
break;
case "action3": // Cancel purchase
handleClearButton(request, response, session);
redirect = "views/home.jsp";
break;
case "action4": // Complete purchase
handleCompletePurchaseButton(request, response, fecha, vendedor, distribuidor, carrito);
handleClearButton(request, response, session);
request.getRequestDispatcher("views/home.jsp").forward(request, response);
//redirect = "views/home.jsp";
break;
default:
// Default logic if necessary
defaultHandler(request, response);
redirect = "views/home.jsp";
break;
}
} else {
// Handle the case where no 'action' value is received
defaultHandler(request, response);
}
response.sendRedirect(redirect);
private void handleCompletePurchaseButton(HttpServletRequest request, HttpServletResponse response, String fecha, String vendedor, String distribuidor, ShoppingCart carrito) throws ServletException, IOException {
GeneralReceipt receipt = createReceipt(fecha, vendedor, distribuidor, carrito);
detailReceipt(receipt.getId(), fecha, vendedor, distribuidor, carrito);
String ticket = generateTicketString(vendedor, distribuidor, carrito, receipt);
generatePDF(response, ticket, distribuidor, fecha);
}
Проблема: Проблема возникает с действием4. В результате операции корректно генерируется PDF-файл, который затем загружается пользователем, но перенаправления на страницу не происходит. Я попробовал следующие решения:
Оба решения приводят к следующей ошибке в консоли:
28-Jun-2024 10:50:29.355 SEVERE [68] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [operacionesRemisionNH1] threw exception
java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed
at org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:486)
at Servlets.operacionesRemisionNH1.generatePDF(operacionesRemisionNH1.java:354)
at Servlets.operacionesRemisionNH1.handleCompletePurchaseButton(operacionesRemisionNH1.java:153)
at Servlets.operacionesRemisionNH1.doPost(operacionesRemisionNH1.java:114)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:232)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:167)
JSP, где я вызываю action4:
<div class = "modal fade" id = "FinalizarCompraModal" tabindex = "-1" aria-labelledby = "FinalizarCompraModalLabel" aria-hidden = "true">
<div class = "modal-dialog modal-dialog-centered">
<div class = "modal-content">
<div class = "modal-header">
<h5 class = "modal-title" id = "FinalizarCompraModalLabel">Purchase Confirmation</h5>
<button type = "button" class = "btn-close" data-bs-dismiss = "modal" aria-label = "Close"></button>
</div>
<div class = "modal-body">
You are about to complete your purchase. Please review your order details. If everything is correct, click 'Confirm' to complete the purchase. If you need to make any changes, click 'Cancel'.
</div>
<div class = "modal-footer">
<button type = "button" class = "btn btn-secondary" data-bs-dismiss = "modal">Cancel</button>
<button type = "submit" name = "action" value = "action4" class = "btn btn-primary">Confirm</button>
</div>
</div>
</div>
</div>
Действительно, вы не можете отправить несколько ответов на один запрос. По сути, после этого вам нужно запустить второй запрос.
Лучше всего добавить определенный файл cookie в ответ, представляющий загрузку файла, и опросить его в JavaScript, а затем выполнить перенаправление в JavaScript, когда файл cookie будет найден.
По сути, в сервлете:
response.setHeader("Content-Disposition", ...);
response.addCookie(new Cookie("download.completed", "true"));
// now write to response.getOutputStream()
А в JSP дайте кнопке загрузки идентификатор, чтобы мы могли ссылаться на нее в JS:
<button type = "submit" id = "yourDownloadButton" ...>
И запустите этот JS, когда контент DOM будет готов, чтобы при нажатии кнопки загрузки запускался опрос файлов cookie. Когда файл cookie будет найден, в этом примере будет показано предупреждение (конечно, в демонстрационных целях вы можете безопасно удалить его), а затем перенаправление на ваш текущий вопрос:
document.getElementById("yourDownloadButton").addEventListener("click", () => {
document.cookie = "download.completed=false";
const downloadCompleteChecker = setInterval(() => {
if (document.cookie.includes("download.completed=true")) {
clearInterval(downloadCompleteChecker);
alert("Download completed!");
window.location = "https://stackoverflow.com/q/78683578";
}
}, 500);
});
Огромное спасибо за подробное объяснение и решение! Я реализовал предложенный подход, используя файл cookie, сигнализирующий о завершении загрузки, и функцию JavaScript для обработки перенаправления. Это сработало отлично