I have a question about servlet redirection to the same initial page.
The following is the scenario:
Suppose a user want to buy an item, so he fills in the amount and submits it. The form is submitted to a servlet and the quantity available is checked against the available in the database. So if the amount of items ordered is more than the available the servlet redirects to the same page but with a message like "item is unavailable".
So my question is how to implement this case. How to redirect to the same initial page with an error message. I don't want to use ajax here.
Here is how I have thought of it as :
1.)should I set a context attribute if error is generated and then check it again in initial page after re-direction and show the message that has been set.
What are the best practices for this kind of events?
The most common and recommended scenario (for the server side validation in Java serlvets/JSP world) is setting some error message as a request attribute (in the request scope) and then outputting this message in a JSP using Expression Language (see the example below). When the error message is not set - nothing will be shown.
But when storing an error message in a request, you should forward a request to the initial page. Setting a request attribute is not suitable when redirecting, because if you use a redirect it will be a totally NEW request and request attributes are reset between requests.
If you want to redirect a request to the referring page (the one from which you submitted data) then you can store an error message in a session (in the session scope), i.e. set a session attribute. But in this case, you also need to remove that attribute from the session when the submitted request is correct, because otherwise an error message will be available as long as the session lives.
As for the context attribute it is meant to be available to the whole web application (application scope) and for ALL users, plus it lives as long as the web application lives, which is hardly useful in your case. If you set an error message as an application attribute it will be visible to ALL users, not only to the one that submitted the wrong data.
OK, here is a primitive example.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Test application</display-name>
<servlet>
<servlet-name>Order Servlet</servlet-name>
<servlet-class>com.example.TestOrderServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Order Servlet</servlet-name>
<url-pattern>/MakeOrder.do</url-pattern>
</servlet-mapping>
</web-app>
order.jsp
<!DOCTYPE html>
<html>
<head>
<title>Test Page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<h1>Test page</h1>
<form action="MakeOrder.do" method="post">
<div style="color: #FF0000;">${errorMessage}</div>
<p>Enter amount: <input type="text" name="itemAmount" /></p>
<input type="submit" value="Submit Data" />
</form>
</body>
</html>
Option №1: setting an error message as a request attribute
package com.example;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import java.io.IOException;
public class TestOrderServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int amount = 0;
try {
amount = Integer.parseInt(request.getParameter("itemAmount"));
} catch (NumberFormatException e) {
// do something or whatever
}
if ((amount > 0) && (amount < 100)) { // an amount is OK
request.getRequestDispatcher("/index.jsp").forward(request, response);
} else { // invalid amount
// Set some error message as a request attribute.
if (amount <= 0) {
request.setAttribute("errorMessage", "Please submit an amount of at least 1");
}
if (amount > 100){
request.setAttribute("errorMessage", "Amount of items ordered is too big. No more than 100 is currently available.");
}
// get back to order.jsp page using forward
request.getRequestDispatcher("/order.jsp").forward(request, response);
}
}
}
Option №2: setting an error message as a session attribute
TestOrderServlet.java
package com.example;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import java.io.IOException;
public class TestOrderServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int amount = 0;
try {
amount = Integer.parseInt(request.getParameter("itemAmount"));
} catch (NumberFormatException e) {
// do something or whatever
}
if ((amount > 0) && (amount < 100)) { // an amount is OK
// If the session does not have an object bound with the specified name, the removeAttribute() method does nothing.
request.getSession().removeAttribute("errorMessage");
request.getRequestDispatcher("/index.jsp").forward(request, response);
} else { // invalid amount
// Set some error message as a Session attribute.
if (amount <= 0) {
request.getSession().setAttribute("errorMessage", "Please submit an amount of at least 1");
}
if (amount > 100){
request.getSession().setAttribute("errorMessage", "Amount of items ordered is too big. No more than 100 is currently available.");
}
// get back to the referer page using redirect
response.sendRedirect(request.getHeader("Referer"));
}
}
}
Related reading:
- How to choose the right bean
scope?
- java.lang.IllegalStateException: Cannot forward after response has
been committed