Java EE Servlet tutorial : Adding create, update and delete to the bookstore listing

From Resin 4.0 Wiki

(Difference between revisions)
Jump to: navigation, search
(Created page with "==Java EE Servlet Tutorial: Implementing a basic CRUD listing== We left off with a basic listing. <code>BookListServlet</code> used a <code>BookRepository</code> object (DAO...")
 
Line 49: Line 49:
 
The link <code>/bookstore/book/</code> (with slash) loads the book listing. The link <code>/bookstore/book?id=1</code> loads
 
The link <code>/bookstore/book/</code> (with slash) loads the book listing. The link <code>/bookstore/book?id=1</code> loads
 
the form page to edit an existing book. To add a new book, we will use the link <code>/bookstore/book</code>.
 
the form page to edit an existing book. To add a new book, we will use the link <code>/bookstore/book</code>.
 +
 +
== Adding a link to the book listing to add a book ==
  
 
====Adding an add book link to book-list.jsp listing====
 
====Adding an add book link to book-list.jsp listing====
Line 61: Line 63:
 
Now we have to links going to the URI /book, we need a Servlet that handles the links.
 
Now we have to links going to the URI /book, we need a Servlet that handles the links.
 
The <code>BookEditorServlet</code> handles both add and the edit book functions.
 
The <code>BookEditorServlet</code> handles both add and the edit book functions.
 +
 +
== Servlet doGet to load a Book form ==
 +
  
 
==== BookEditorServlet.java doGet ====
 
==== BookEditorServlet.java doGet ====
Line 127: Line 132:
  
 
</pre>
 
</pre>
 +
 +
== Rendering the book form HTML ==
  
  
Line 231: Line 238:
  
 
The <code>doPost</code> method of <code>BookEditorServlet</code> handles the form submission as follows:
 
The <code>doPost</code> method of <code>BookEditorServlet</code> handles the form submission as follows:
 +
 +
== Creating a doPost method to handle the form submission ==
  
 
==== BookEditorServlet.java doPost ====
 
==== BookEditorServlet.java doPost ====

Revision as of 00:00, 1 May 2012

Contents

Java EE Servlet Tutorial: Implementing a basic CRUD listing

We left off with a basic listing. BookListServlet used a BookRepository object (DAO) to load a list of books and then delegated to book-list.jsp to render the book listing.

In this step, we want to add a link to the book listing so when the user clicks it a form gets rendered so that they can edit the details of book. Also we want an add link so that the end user can add a new book to the listing.

Adding a link to the book listing to edit a book

Change the code that looks like this in book-list.jsp:

...
	<c:forEach var="book" items="${books}">
		<tr>
			<td>${book.title}</td>
...

To this


Adding an edit book link to book-list.jsp listing

...
	<c:forEach var="book" items="${books}">
	     <tr>
			<td><a href="${pageContext.request.contextPath}/book?id=${book.id}">${book.title}</a></td>
...			

The EL expression ${pageContext.request.contextPath} refers to the URI you have the war file mapped to in the Servlet container. The default URI for a webapp is its war file name so our war file name is bookstore so a rendered URL will look like this:

	...
		<tr>
			<td><a href="/bookstore/book?id=0">War and Peace</a></td>
	...
		<tr>
			<td><a href="/bookstore/book?id=1">Pride and Prejudice</a></td>
	...

The link /bookstore/book/ (with slash) loads the book listing. The link /bookstore/book?id=1 loads the form page to edit an existing book. To add a new book, we will use the link /bookstore/book.

Adding a link to the book listing to add a book

Adding an add book link to book-list.jsp listing

Before the table add this HTML code to add a new book:

...
<a href="${pageContext.request.contextPath}/book">Add Book</a>
...			

Now we have to links going to the URI /book, we need a Servlet that handles the links. The BookEditorServlet handles both add and the edit book functions.

Servlet doGet to load a Book form

BookEditorServlet.java doGet

package com.bookstore.web;

...

@WebServlet("/book")
public class BookEditorServlet extends HttpServlet {

	@Inject
	private BookRepository bookRepo;
		
	private SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
	
    ...
	/** Prepare the book form before we display it. */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String id = request.getParameter("id");

		if (id != null && !id.isEmpty()) {
			Book book = bookRepo.lookupBookById(id);
			request.setAttribute("book", book);
			request.setAttribute("bookPubDate", dateFormat.format(book.getPubDate()));
		}

		/* Redirect to book-form. */
		getServletContext().getRequestDispatcher("/WEB-INF/pages/book-form.jsp").forward(
				request, response);

	}
}

Notice we use @WebServlet("/book") to map BookEditorServlet to the URI /book. It is common to load a form from a doGet method, and to handle the form submission via doPost. Following REST and HTTP principles GET operations reads data, and POST data modifies data. The doGet method uses the id being empty or not to determine if this is a load "Add Employee Form" or load "Update Employee Form" operation. The doGet method also converts the date into a format that is easy for the end user to modify and it also maps the book into request scope as follows:

BookEditorServlet.java doGet() delegate to book-form.jsp page

			Book book = bookRepo.lookupBookById(id);
			request.setAttribute("book", book);
			request.setAttribute("bookPubDate", dateFormat.format(book.getPubDate()));



In the model 2 architecture, the Servlet tier prepares the form data before a form loads to be rendered and edited correctly.

To render the HTML form, the servlet delegates to book-form.jsp as follows:

BookEditorServlet.java doGet() delegate to book-form.jsp page

		/* Redirect to book-form. */
		getServletContext().getRequestDispatcher("/WEB-INF/pages/book-form.jsp").forward(
				request, response);

Rendering the book form HTML

The book-form.jsp has the HTML code to render a form as follows:

book-form.jsp Renders form to update or add a Book

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML>
<html>
<head>
<title>Book Form</title>
</head>

<body>

	<h1>Book Form</h1>


	<form method="post"
		action="${pageContext.request.contextPath}/book">
		<fieldset>
			<legend>
				<c:choose>
					<c:when test="${not empty book.id }">
						Updating Book
					</c:when>
					<c:otherwise>
						Adding Book
					</c:otherwise>
				</c:choose>
			</legend>

			<div>
				<label for="title">Title</label> <input type="text" name="title"
					id="title" value="${book.title}" />
			</div>

			<div>
				<label for="description">Description</label>
				<textarea name="description" id="description" rows="2" cols="60">${book.description}</textarea>
			</div>

			<div>
				<label for="price">Price $</label> <input name="price" id="price" 
					value="${book.price}" />
			</div>

			<div>
				<label for="pubDate">Publication Date</label> 
				<input name="pubDate" id="pubDate" 
					value="${bookPubDate}" />
					<label class="after">(MM/DD/YYYY)</label>
			</div>

			<c:if test="${not empty book.id}">
				<input type="hidden" name="id" value="${book.id}" />
			</c:if>

		</fieldset>

		<div class="button-row">
			<a href="${pageContext.request.contextPath}/book/">Cancel</a> or <input type="submit" value="Submit" />
		</div>
	</form>

</body>
</html>
The
book-form.jsp
uses JSTL c:choose, c:otherwise to display whether we are adding a new book or updating a book as follows:

book-form.jsp using JSTL c:choose to display update or add status

...
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
...
			<legend>
				<c:choose>
					<c:when test="${not empty book.id }">
						Updating Book
					</c:when>
					<c:otherwise>
						Adding Book
					</c:otherwise>
				</c:choose>
			</legend>

...

If the book.id property is present the test "Updating Book" is rendered.

Also, the form renders a hidden id property if it is doing an edit/update operation as follows:

book-form.jsp using JSTL c:if to hidden id field for edit/update operation

			<c:if test="${not empty book.id}">
				<input type="hidden" name="id" value="${book.id}" />
			</c:if>

The doPost method of BookEditorServlet handles the form submission as follows:

Creating a doPost method to handle the form submission

BookEditorServlet.java doPost

package com.bookstore.web;

...

@WebServlet("/book")
public class BookEditorServlet extends HttpServlet {

	@Inject
	private BookRepository bookRepo;
		
	
    ...
    /**
	 * Handles posting an HTML book form. If the id is null then it is an
	 * "add book", if the id is set then it is an "update book"
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		String title = request.getParameter("title");
		String description = request.getParameter("description");
		String price = request.getParameter("price");
		String pubDate = request.getParameter("pubDate");
		

		String id = request.getParameter("id");
		if (id == null || id.isEmpty()) {
			bookRepo.addBook(title, description, price, pubDate);
		} else {
			bookRepo.updateBook(id, title, description, price, pubDate);
		}

		response.sendRedirect(request.getContextPath() + "/book/");
	}
    ...
}

Notice that if the id is null then BookEditorServlet.doPost calls bookRepo.addBook, otherwise it calls bookRepo.updateBook. Once the form handling is done, doPost redirects to /book/. A redirect means an extra hit to the server, since we are basically telling the browser to load another link. The astute reader may wonder why we don't just do a forward like we did in the doGet. The answer is bookmarking. The URL /book/ (ending in slash) represents a collection of books, while /book (no slash) represents a single book (using REST style URL). If we did a forward, then after the form submission the browser would show the listing, but under the URI /book instead of /book/. If the ender user linked to /book, it would not take them back to the listing but back to a form, which not correct. This is why we do a sendRedirect instead of a forward.

Now we have an add/edit/update/read/ and listing. It is everything you could want from a CRUD listing.

At this point, we don't do much validation. We will add this in a later lesson.

Personal tools
TOOLBOX
LANGUAGES