Doget and Dopost in Servlets

doGet and doPost in Servlets

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 tutorials (check the chapter "Trails Covering the Basics") and how to use JSP/Servlets the right way using those tutorials.

See also:

  • Our servlets wiki page
  • Java EE web development, where do I start and what skills do I need?
  • Servlet returns "HTTP Status 404 The requested resource (/servlet) is not available"
  • Show JDBC ResultSet in HTML in JSP page using MVC and DAO pattern

Update: as per the update of your question (which is pretty major, you should not remove parts of your original question, this would make the answers worthless .. rather add the information in a new block) , 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 parse the request body yourself. Usually you use the Apache Commons FileUpload there for, but if you're already on fresh new Servlet 3.0 API, then you can just use builtin facilities starting with HttpServletRequest#getPart(). See also this answer for a concrete example: How to upload files to server using JSP/Servlet?

What's the difference between doGet()/doPost() and processRequest()?

What's the difference?

It's just a matter of moving common code to one place, for example:

public class TestServlet extends HttpServlet 
{

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().println("Welcome to TestSevlet");
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}

*Note: doPost() and doGet() are part of the Servlet interface, and processRequest() is just a frequently used name for a helper method and is not part of any interface

Should you use processRequest()?

It depends how your Servlet is supposed to behave and how your servlet is invoked, if you want to have different behavior on POST requests than on GET requests, then implement them separately. If your servlet should have the same behavior whether a GET or POST is invoked on it, then route them to the same processRequest() method.

In most cases (probably 90% of the time) yes, you can route doGet() and doPost() to a single processRequest() method.

An example of where you would NOT want to route both to a processRequest() method is if you want to upload a file for POST requests and view some data for a GET request.

Is processRequest() considered good practice?

If GET and POST are doing the same thing, then yes absolutely. In fact, Arun Gupta (one of the main spec leads for Java EE) uses this pattern in his samples.

When to use doGet, doPost and service

There's the technically differences you mentioned and there's part where we're talking about REST metaphers.

Beside POST and GET, there's PUT and DELETE too. You should use GET for operations which don't alter your data, POST for creation and PUT for update of data. DELETE is obviously for deletion of data.

Servlets doGet doPost AND?

The 1% doesn't make use of abstract HttpServlet class. So they use Servlet interface without extending HttpServlet.

Currently in the Java EE API, there's only one other Servlet which does that: the FacesServlet which is the core controller behind the Java EE provided MVC framework JavaServer Faces (JSF). JSF enables you to skip all the tedious process and the boilerplate code which is necessary to gather, convert and validate parameters, update the model values and invoke specific action methods.

But at the time of writing this book, the author likely didn't realize that. As of now, JSF certainly doesn't account for only 1%. In theory it's possible to implement Servlet for other protocols than HTTP, like FTP. This is not provided by the standard Java EE API, but there are some 3rd party "FtpServlet" classes out. And I believe some Portlet APIs also use a non-HttpServlet class (they just implement Servlet and don't extend HttpServlet).

As to the HTTP methods, next to HTTP GET and POST there are also HEAD, PUT, OPTIONS, etc. But I think 0.1% is heavily underestimated. The HEAD is definitely much more often used, think of servletcontainer's own DefaultServlet (like as Tomcat has). The HEAD plays an important role in browser cache requests. But when it comes to "homegrown" servlets, then it are indeed GET and POST which gets the lone attention.

See also:

  • What is the difference between JSP, Servlets and JSF?

doPost method in servlet not getting called

Your HTML form submit button is incorrect: fix type attribute.
Try:

<input type="submit" name="submit" value="Submit"/>


Related Topics



Leave a reply



Submit