servlets

doGet and doPost in Servlets


I've developed an html page that sends information to a servlet. In the servlet, I was using the method service to get that information and perform operations.

I've read that other methods that I could use are doGet and doPost. Should I use these methods or is it ok to use the service method?

Another question is about how to use the doPost method. In the servlet I'm using the following piece of code to retrieve information:

for ( Enumeration e = req.getParameterNames(); e.hasMoreElements();) 
{
    String param = (String) e.nextElement();                      
    String value = req.getParameter(param);   

    if(param.compareTo("realname") == 0)
    {
        id = value;
    }
    else if(param.compareTo("mypassword") == 0)
    {
        password = value;
    }
}
        
id = req.getParameter("realname");
password = req.getParameter("mypassword");

This code is used in :

public void doPost(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException 
{
    ....
}

The method doGet looks like:

public void doGet(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException 
{       
    doPost(req, res);
}

When I use the method get (in the html code) I'm able to get these parameters in the servlet, however, when I use the methos post I can see that there are no iterations in the 'for' loop and the values of id and password are set to null. Does anybody know why?

Update: the html page code that calls the Servlet is:

<form action="identification" method="post" enctype="multipart/form-data">
    User Name: <input type="text" name="realname">
    Password: <input type="password" name="mypassword">
    <input type="submit" value="Identification">
</form> 

Solution

  • Introduction

    You should use doGet() when you want to intercept on HTTP GET requests. You should use doPost() when you want to intercept on HTTP POST requests. That's all. Do not port the one to the other or vice versa (such as in Netbeans' unfortunate auto-generated processRequest() method). This makes no utter sense.

    GET

    Usually, HTTP GET requests are idempotent. I.e. you get exactly the same result everytime you execute the request (leaving authorization/authentication and the time-sensitive nature of the page —search results, last news, etc— outside consideration). We can talk about a bookmarkable request. Clicking a link, clicking a bookmark, entering raw URL in browser address bar, etcetera will all fire a HTTP GET request. If a Servlet is listening on the URL in question, then its doGet() method will be called. It's usually used to preprocess a request. I.e. doing some business stuff before presenting the HTML output from a JSP, such as gathering data for display in a table.

    @WebServlet("/products")
    public class ProductsServlet extends HttpServlet {
    
        @EJB
        private ProductService productService;
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            List<Product> products = productService.list();
            request.setAttribute("products", products); // Will be available as ${products} in JSP
            request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response);
        }
    
    }
    

    Note that the JSP file is explicitly placed in /WEB-INF folder in order to prevent endusers being able to access it directly without invoking the preprocessing servlet (and thus end up getting confused by seeing an empty table).

    <table>
        <c:forEach items="${products}" var="product">
            <tr>
                <td>${product.name}</td>
                <td><a href="product?id=${product.id}">detail</a></td>
            </tr>
        </c:forEach>
    </table>
    

    Also view/edit detail links as shown in last column above are usually idempotent.

    @WebServlet("/product")
    public class ProductServlet extends HttpServlet {
    
        @EJB
        private ProductService productService;
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            Product product = productService.find(request.getParameter("id"));
            request.setAttribute("product", product); // Will be available as ${product} in JSP
            request.getRequestDispatcher("/WEB-INF/product.jsp").forward(request, response);
        }
    
    }
    
    <dl>
        <dt>ID</dt>
        <dd>${product.id}</dd>
        <dt>Name</dt>
        <dd>${product.name}</dd>
        <dt>Description</dt>
        <dd>${product.description}</dd>
        <dt>Price</dt>
        <dd>${product.price}</dd>
        <dt>Image</dt>
        <dd><img src="productImage?id=${product.id}" /></dd>
    </dl>
    

    POST

    HTTP POST requests are not idempotent. If the enduser has submitted a POST form on an URL beforehand, which hasn't performed a redirect, then the URL is not necessarily bookmarkable. The submitted form data is not reflected in the URL. Copypasting the URL into a new browser window/tab may not necessarily yield exactly the same result as after the form submit. Such an URL is then not bookmarkable. If a Servlet is listening on the URL in question, then its doPost() will be called. It's usually used to postprocess a request. I.e. gathering data from a submitted HTML form and doing some business stuff with it (conversion, validation, saving in DB, etcetera). Finally usually the result is presented as HTML from the forwarded JSP page.

    <form action="login" method="post">
        <input type="text" name="username">
        <input type="password" name="password">
        <input type="submit" value="login">
        <span class="error">${error}</span>
    </form>
    

    ...which can be used in combination with this piece of Servlet:

    @WebServlet("/login")
    public class LoginServlet extends HttpServlet {
    
        @EJB
        private UserService userService;
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            User user = userService.find(username, password);
    
            if (user != null) {
                request.getSession().setAttribute("user", user);
                response.sendRedirect("home");
            }
            else {
                request.setAttribute("error", "Unknown user, please try again");
                request.getRequestDispatcher("/login.jsp").forward(request, response);
            }
        }
    
    }
    

    You see, if the User is found in DB (i.e. username and password are valid), then the User will be put in session scope (i.e. "logged in") and the servlet will redirect to some main page (this example goes to http://example.com/contextname/home), else it will set an error message and forward the request back to the same JSP page so that the message get displayed by ${error}.

    You can if necessary also "hide" the login.jsp in /WEB-INF/login.jsp so that the users can only access it by the servlet. This keeps the URL clean http://example.com/contextname/login. All you need to do is to add a doGet() to the servlet like this:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
    }
    

    (and update the same line in doPost() accordingly)

    That said, I am not sure if it is just playing around and shooting in the dark, but the code which you posted doesn't look good (such as using compareTo() instead of equals() and digging in the parameternames instead of just using getParameter() and the id and password seems to be declared as servlet instance variables — which is NOT threadsafe). So I would strongly recommend to learn a bit more about basic Java SE API using the Oracle Java tutorials (check the chapter "Trails Covering the Basics") and how to use Servlets the right way using Eclipse Jakarta EE tutorials.

    See also:


    Update: as per the update of your question, it turns out that you're unnecessarily setting form's encoding type to multipart/form-data. This will send the request parameters in a different composition than the (default) application/x-www-form-urlencoded which sends the request parameters as a query string (e.g. name1=value1&name2=value2&name3=value3). You only need multipart/form-data whenever you have a <input type="file"> element in the form to upload files which may be non-character data (binary data). This is not the case in your case, so just remove it and it will work as expected. If you ever need to upload files, then you'll have to set the encoding type so and put the @MultipartConfig annotation on the servlet class in order to get getParameter() to work. See also this answer for a concrete example: How can I upload files to a server using JSP/Servlet?