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
Line 293: Line 293:
  
 
At this point, we don't do much validation. We will add this in a later lesson.
 
At this point, we don't do much validation. We will add this in a later lesson.
 +
 +
== Quick review of what we have so far ==
 +
 +
We have created the following files for this bookstore example:
 +
 +
<pre>
 +
$ find .
 +
.
 +
./WebContent/WEB-INF/pages/book-form.jsp          Book Form
 +
./WebContent/WEB-INF/pages/book-list.jsp              Book Listing
 +
./src/META-INF/beans.xml                                        Needed for Java EE dependency injection (CDI)
 +
./src/com/bookstore/Book.java                                Domain/model object
 +
./src/com/bookstore/BookRepositoryImpl.java          Repository implementation using Java collections (just for testing)
 +
./src/com/bookstore/BookRepository.java                Interface to Book Repository so we can swap it out with JDBC, JPA, JCache and MongoDB version later
 +
./src/com/bookstore/web/BookEditorServlet.java      Servlet that loads Book (doGet) form and handles Book form submissions (doPost).
 +
./src/com/bookstore/web/BookListServlet.java          Servlet that looks up a list of books and displays the listing
 +
</pre>

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.

Quick review of what we have so far

We have created the following files for this bookstore example:

$ find .
.
./WebContent/WEB-INF/pages/book-form.jsp           Book Form
./WebContent/WEB-INF/pages/book-list.jsp              Book Listing
./src/META-INF/beans.xml                                        Needed for Java EE dependency injection (CDI)
./src/com/bookstore/Book.java                                 Domain/model object
./src/com/bookstore/BookRepositoryImpl.java          Repository implementation using Java collections (just for testing)
./src/com/bookstore/BookRepository.java                 Interface to Book Repository so we can swap it out with JDBC, JPA, JCache and MongoDB version later 
./src/com/bookstore/web/BookEditorServlet.java      Servlet that loads Book (doGet) form and handles Book form submissions (doPost).
./src/com/bookstore/web/BookListServlet.java          Servlet that looks up a list of books and displays the listing
Personal tools
TOOLBOX
LANGUAGES