Building a Small MVC Web App

Harry · 11 Sep 2026 · 10 views

Building a Small MVC Web App

Let us tie everything together by building a small MVC web application - a book catalog with list, view, and search functionality. This demonstrates how servlets, JSP, JSTL, and sessions work together.

The Model Layer

Start with a simple POJO and a service class:

public class Book {
    private Long id;
    private String title;
    private String author;
    private double price;
    // constructor, getters, setters
}

public class BookService {
    private static final List<Book> BOOKS = List.of(
        new Book(1L, "Clean Code", "Robert Martin", 29.99),
        new Book(2L, "Effective Java", "Joshua Bloch", 34.99),
        new Book(3L, "Design Patterns", "Gang of Four", 39.99)
    );
    public List<Book> findAll() { return BOOKS; }
    public Book findById(long id) {
        return BOOKS.stream().filter(b -> b.getId() == id).findFirst().orElse(null);
    }
    public List<Book> search(String q) {
        return BOOKS.stream()
            .filter(b -> b.getTitle().toLowerCase().contains(q.toLowerCase()))
            .toList();
    }
}

The Controller Layer

A single servlet routes requests based on the URL path:

@WebServlet("/books/*")
public class BookController extends HttpServlet {
    private final BookService bookService = new BookService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        String path = req.getPathInfo();
        if (path == null || "/".equals(path)) {
            req.setAttribute("books", bookService.findAll());
            req.getRequestDispatcher("/WEB-INF/views/book-list.jsp")
               .forward(req, resp);
        } else {
            long id = Long.parseLong(path.substring(1));
            req.setAttribute("book", bookService.findById(id));
            req.getRequestDispatcher("/WEB-INF/views/book-detail.jsp")
               .forward(req, resp);
        }
    }
}

The View Layer

JSP files use JSTL to render the data:

<%@ taglib uri="jakarta.tags.core" prefix="c" %>
<%@ taglib uri="jakarta.tags.fmt" prefix="fmt" %>
<%@ include file="/WEB-INF/fragments/header.jsp" %>
<h1>Book Catalog</h1>
<c:forEach items="${books}" var="book">
    <div class="book-card">
        <h2><a href="books/${book.id}">${book.title}</a></h2>
        <p>by ${book.author}</p>
        <p><fmt:formatNumber value="${book.price}" type="currency"/></p>
    </div>
</c:forEach>
<%@ include file="/WEB-INF/fragments/footer.jsp" %>

Project Structure

src/main/java/com/example/
    model/Book.java
    service/BookService.java
    controller/BookController.java
src/main/webapp/
    WEB-INF/
        web.xml
        views/
            book-list.jsp
            book-detail.jsp
        fragments/
            header.jsp
            footer.jsp

This structure scales. As the application grows, add more servlets for different resources, more JSP views, and a real database in the model layer.

Key Points

  • MVC separates the application into Model (data), Controller (logic), and View (presentation).
  • Servlets act as controllers that process requests and forward to JSP views.
  • JSP with JSTL handles presentation without scriptlets.
  • Place JSP files under WEB-INF/ to prevent direct browser access.
  • This pattern is the foundation of Spring MVC and other Java web frameworks.
Share this post:

Comments (0)

Please login or register to comment.