Bill Digman is a Java EE / Servlet enthusiast and Open Source enthusiast who loves working with Caucho's Resin Servlet Container, a Java EE Web Profile Servlet Container. Bill has posted 12 posts at DZone. You can read more from them at their website. View Full User Profile

Java EE: JSP 2.2 and Servlets 3.0 tutorial with Resin Servlet Container Part Two

11.01.2012
| 5765 views |
  • submit to reddit

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
./WebContent/WEB-INF/pages/book-form.jsp full listing
<%@ 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 prebuffer_12lt;/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>
./WebContent/WEB-INF/pages/book-list.jsp full listing
<%@ 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 listing</title>
</head>
<body>




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




<table>
	<tr>
		<th>Title</th>
		<th>Description</th>
		<th>Price</th>
		<th>Publication Date</th>
	</tr>
	
	<c:forEach var="book" items="${books}">
		<tr>
			<td><a href="${pageContext.request.contextPath}/book?id=${book.id}">${book.title}</a></td>
			<td>${book.description}</td>
			<td>${book.price}</td>
			<td>${book.pubDate}</td>
		</tr>
	</c:forEach>
</table>




</body>
</html>








./src/META-INF/beans.xml  full listing
<?xml version="1.0" encoding="UTF-8"?>
<beans 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/beans_1_0.xsd">
</beans>
./src/com/bookstore/Book.java
package com.bookstore;




import java.math.BigDecimal;
import java.util.Date;




public class Book implements Cloneable {




	private String title; 
	private String description;
	private BigDecimal price;
	private Date pubDate;
	private String id;
	
	public Book(String id, String title, String description, BigDecimal price, Date pubDate) {
		this.id = id;
		this.title = title;
		this.description = description;
		this.price = price;
		this.pubDate = pubDate;
	}
	
	public Book () {
		
	}




	public String getTitle() {
		return title;
	}




	public void setTitle(String title) {
		this.title = title;
	}




	public String getDescription() {
		return description;
	}




	public void setDescription(String description) {
		this.description = description;
	}




	public BigDecimal getPrice() {
		return price;
	}




	public void setPrice(BigDecimal price) {
		this.price = price;
	}




	public Date getPubDate() {
		return pubDate;
	}




	public void setPubDate(Date pubDate) {
		this.pubDate = pubDate;
	}




	public String getId() {
		return id;
	}




	public void setId(String id) {
		this.id = id;
	}
	
	public Book cloneMe()  {
		try {
			return (Book) super.clone();
		} catch (CloneNotSupportedException e) {
			return null;  
		}
	}
	
	@Override
	public String toString() {
		return "Book [title=" + title + ", description=" + description
				+ ", price=" + price + ", pubDate=" + pubDate + ", id=" + id
				+ "]";
	}




}




./src/com/bookstore/BookRepositoryImpl.java  full listing  (testing only)
package com.bookstore;




import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.math.BigDecimal;




import javax.enterprise.context.ApplicationScoped;




@ApplicationScoped
public class BookRepositoryImpl implements BookRepository {




	private SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
	private int count;
	private Map<String, Book> idToBookMap = new HashMap<String, Book>();




	public BookRepositoryImpl()  {
		synchronized (this) {
			books(book("War and Peace", "blah blah blah", "5.50", "5/29/1970"),
					book("Pride and Prejudice", "blah blah blah", "5.50", "5/29/1960"),
					book("book1", "blah blah blah", "5.50", "5/29/1960"),
					book("book2", "blah blah blah", "5.50", "5/29/1960"),
					book("book3", "blah blah blah", "5.50", "5/29/1960"),
					book("book4", "blah blah blah", "5.50", "5/29/1960"),
					book("book5", "blah blah blah", "5.50", "5/29/1960"),
					book("book6", "blah blah blah", "5.50", "5/29/1960"),
					book("book7", "blah blah blah", "5.50", "5/29/1960"),
					book("book8", "blah blah blah", "5.50", "5/29/1960"),
					book("book9", "blah blah blah", "5.50", "5/29/1960"),
					book("Java for dummies", "blah blah blah", "1.99", "5/29/1960"));
		}
	}




	private Book book(String title, String description, String aPrice,
			String aPubDate)  {




		Date pubDate = null;
		BigDecimal price = null;
		
		try {
			price = new BigDecimal(aPrice);
		}catch (Exception ex) {
		}
		
		try {
			pubDate = dateFormat.parse(aPubDate);
		}catch (Exception ex) {
		}
		
		return new Book("" + (count++), title, description, price, pubDate);
		
	}




	private void books(Book... books) {
		for (Book book : books) {
			doAddBook(book);
		}
	}




	private void doAddBook(Book book) {
		synchronized (this) {
			this.idToBookMap.put(book.getId(), book);
		}
	}




	@Override
	public Book lookupBookById(String id)  {
		synchronized (this) {
			return this.idToBookMap.get(id).cloneMe();
		}
	}




	@Override
	public void addBook(String title, String description, String price,
			String pubDate)  {
		doAddBook(book(title, description, price, pubDate));
	}




	@Override
	public void updateBook(String id, String title, String description,
			String price, String pubDate) {
		Book book = book(title, description, price, pubDate);
		synchronized (this) {
			book.setId(id);
			this.idToBookMap.put(id, book);
		}
	}




	private List<Book> doListBooks()  {
		List<Book> books;
		synchronized (this) {




			books = new ArrayList<Book>(this.idToBookMap.size());
			for (Book book : this.idToBookMap.values()) {
				books.add(book.cloneMe());
			}
		}
		return books;
	}
	
	public List<Book> listBooks() {
		
		List<Book> books = doListBooks();




		Collections.sort(books, new Comparator<Book>() {
			public int compare(Book bookA, Book bookB) {
				return bookA.getId().compareTo(bookB.getId());
			}
		});
		return books;
	}




	@Override
	public void removeBook(String id)  {
		synchronized(this) {
			this.idToBookMap.remove(id);
		}
	}




}




./src/com/bookstore/BookRepository.java full listing
package com.bookstore;




import java.util.List;




public interface BookRepository {
	Book lookupBookById(String id);




	void addBook(String title, String description,
			String price, String pubDate);




	void updateBook(String id, String title,
			String description, String price, String pubDate);
	
	void removeBook(String id);








	List<Book> listBooks();




}
./src/com/bookstore/web/BookEditorServlet.java
package com.bookstore.web;




import java.io.IOException;
import java.text.SimpleDateFormat;




import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;




import com.bookstore.Book;
import com.bookstore.BookRepository;




/**
 * Servlet implementation class BookEditorServlet
 */
@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);




	}
	
    /**
	 * 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/");
	}
}




./src/com/bookstore/web/BookListServlet.java
package com.bookstore.web;




import java.io.IOException;




import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;




import com.bookstore.BookRepository;




@WebServlet("/book/")
public class BookListServlet extends HttpServlet {
	
	@Inject 
	private BookRepository bookRepo;




	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setAttribute("books", bookRepo.listBooks());
		getServletContext().getRequestDispatcher("/WEB-INF/pages/book-list.jsp").forward(request, response);
	}




}




Technical debt

We have accumulated some technical debt. Our UI is just plain HTML, it has no styling. This is probably and oversight.  There is no footer, or header. There probably should be some sort of header area that has a link to the home page, and a footer with a copyright notice or something. The book listing does not format the price of the date, it should.

We will address these issues and others in the coming lessons.

 

Bill Digman is a Java EE / Servlet enthusiast and Open Source enthusiast who loves working with Caucho's Resin Servlet Container, a Java EE Web Profile Servlet Container.

Caucho's Resin OpenSource Servlet ContainerJava EE Web Profile Servlet ContainerJavaLobby Article: Java EE Tutorial Covering JSP and Servlets Part OneCaucho Wiki Java EE Servlet Tutorial: Using JSPs to create header, footer area, formatting, and basic css for bookstore
AttachmentSize
Java EE Tutorial covering JSP and Servlets PDF.pdf671.11 KB
Published at DZone with permission of its author, Bill Digman.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)