Java webapp with Stripes, MyBatis, & Derby
last modified July 6, 2020
In this tutorial, we create a Java web application with Stripes, MyBatis, and Derby. We use NetBeans to build the application. Apache Tomcat is used as the JSP and servlet container. The project sources are available at the author's Github repository.
Stripes is an open source lightweight Java web application framework. The goal of Stripes is to make Servlet/JSP based web development in Java easy, intuitive, and straightforward. Stripes is an action based MVC (Model View Controller) framework. It runs in a JEE web container, uses minimum configuration files, and has a flexible and simple parameter binding.
MyBatis is a Java persistence framework that couples objects with stored procedures or SQL statements using an XML descriptor or annotations. Unlike ORM frameworks, MyBatis does not map Java objects to database tables but Java methods to SQL statements. MyBatis allows to use all database functionality like stored procedures, views, queries of any complexity and vendor proprietary features.
Derby is a relational database management system written in Java. Oracle distributes the same binaries under the name Java DB. Derby has a small footprint around 2MB. The database format used by Derby is portable and platform independent.
Books application
We create a new web application in NetBeans. In the application, we will be able to add new books to the database, select single books by their ID, and select all books in the table. The project needs Stripes, MyBatis, and JSTL libraries. The first three JARs are MyBatis libraries, the next three are Stripes' libraries. We must dowloand them from their project pages. The JSTL JARs are available with NebBeans.

In the NetBeans Services tab, we expand the Databases node and right-click on the Java DB
node and select Create Database option. The database name will be books
, the user
and password app
and app
.
CREATE TABLE Books(Id INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1), Author VARCHAR(30), Title VARCHAR(60), Published INTEGER, Remark VARCHAR(150)); INSERT INTO Books(Author, Title, Published, Remark) VALUES ('Leo Tolstoy', 'War and Peace', 1869, 'Napoleonic wars'); INSERT INTO Books(Author, Title, Published, Remark) VALUES ('Leo Tolstoy', 'Anna Karenina', 1878, 'Greatest book of love'); INSERT INTO Books(Author, Title, Published, Remark) VALUES ('Jeff Prosise', 'Programming Windows with MFC', 1999, 'Classic book about MFC'); INSERT INTO Books(Author, Title, Published, Remark) VALUES ('Tom Marrs', 'JBoss at Work', 2005, 'JBoss practical guide'); INSERT INTO Books(Author, Title, Published, Remark) VALUES ('Debu Panda', 'EJB3 in Action', 2007, 'Introduction to Enterprice Java Beans');
We create a new database connection to the created database and execute this SQL code.
We have a Books
table with a few books in it.
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <filter> <display-name>Stripes Filter</display-name> <filter-name>StripesFilter</filter-name> <filter-class>net.sourceforge.stripes.controller.StripesFilter</filter-class> <init-param> <param-name>ActionResolver.Packages</param-name> <param-value>com.zetcode.action</param-value> </init-param> </filter> <filter-mapping> <filter-name>StripesFilter</filter-name> <url-pattern>*.jsp</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping> <filter-mapping> <filter-name>StripesFilter</filter-name> <servlet-name>StripesDispatcher</servlet-name> <dispatcher>REQUEST</dispatcher> </filter-mapping> <servlet> <servlet-name>StripesDispatcher</servlet-name> <servlet-class>net.sourceforge.stripes.controller.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>StripesDispatcher</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
In the web.xml
deployment descriptor, we set up the Stripes framework.
The index.jsp
file is the default home page file. In the com.zetcode.action
we have our ActionBeans
.
Resources
In the resources
directory, we have three files. The resources
directory
is created by right-clicking on the project file and selecting Properties. In the sources
category, we add a new source package folder.

The BookMapper.xml
and mybatis-config.xml
are XML files used by MyBatis.
The StripesResources.properties
is the default resource bundle file for the Stripes
framework. It contains error messages and labels for the application.
It is available in the lib
subdirectory of the Stripes download file.
Presentation layer
The presentation layer consists of six JSP pages. The index.jsp
is the
default home page of the application. The addBook.jsp
is a page to add a new book to the database and the findBook.jsp
is
a page to find a book by its ID. The bookAdded.jsp
shows a message
after a book was successfully inserted into the database, the showOneBook.jsp
displays the selected book, and the showAllBooks.jsp
displays all books
from the database.
<%@taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld"%> <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Welcome page</title> </head> <body> <stripes:link href="addBook.jsp"> Add a new book </stripes:link> <stripes:link href="findBook.jsp"> Find one book </stripes:link> <stripes:link beanclass="com.zetcode.action.SelectAllBooksActionBean"> Show all books </stripes:link> </body> </html>
The index.jsp
contains Stripes links to two JSP pages to add a new book
and find a book and a link to an ActionBean
to show all books.
The <%@taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld"%>
declares the tags used by Stripes, including <stripes:link>
.
<%@taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld"%> <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Find a book</title> </head> <body> <stripes:form beanclass="com.zetcode.action.SelectOneBookActionBean"> <stripes:errors/> Book ID: <stripes:text name="bookId"/><br> <stripes:submit name="save" value="Submit"/> </stripes:form> </body> </html>
In the findBook.jsp
we have a form to find a book by its ID.
The form consists of a text field and a Submit button. The inserted value is
validated; if the user adds an invalid value, the application returns an error
message.
<%@taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld"%> <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Add new book</title> </head> <body> <stripes:form beanclass="com.zetcode.action.AddBookActionBean"> <stripes:errors/> Author: <stripes:text name="author"/><br> Title: <stripes:text name="title"/><br> Year of publishing: <stripes:text name="published"/><br> Remark <stripes:text name="remark"/><br> <stripes:submit name="save" value="Submit"/> </stripes:form> </body> </html>
The addBook.jsp
adds a new book to the database. It contains a form
with four text fields for the book object. The ID is auto-generated by Derby database.
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Book added</title> </head> <body> <h3>Book added to database</h3> </body> </html>
When a new book is added to the database, the application returns bookAdded.jsp
,
which contains a simple message.
<%@page contentType="text/html" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Show all books</title> </head> <body> <h3>All books</h3> <table> <thead> <tr> <th>Id</th> <th>Author</th> <th>Title</th> <th>Published</th> <th>Remark</th> </tr> </thead> <c:forEach items="${actionBean.books}" var='book'> <tr> <td> <c:out value="${book.id}"/> </td> <td> <c:out value="${book.author}"/> </td> <td> <c:out value="${book.title}"/> </td> <td> <c:out value="${book.published}"/> </td> <td> <c:out value="${book.remark}"/> </td> </tr> </c:forEach> </table> </body> </html>
The showAllBooks.jsp
displays all books retrieved from the database.
The <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
directive
declares the JSTL core tags, including <c:forEach>
and <c:out>
.
The returned data can be accessed with the ${actionBean}
expression, where actionBean
is the action bean that forwarded the view (i.e. this JSP page). In this case, the action bean
is SelectAllBooksActionBean
.
<%@page contentType="text/html" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Show one book</title> </head> <body> <h3>A book</h3> <table> <thead> <tr> <th>Id</th> <th>Author</th> <th>Title</th> <th>Published</th> <th>Remark</th> </tr> </thead> <tr> <td> <c:out value="${actionBean.book.id}"/> </td> <td> <c:out value="${actionBean.book.author}"/> </td> <td> <c:out value="${actionBean.book.title}"/> </td> <td> <c:out value="${actionBean.book.published}"/> </td> <td> <c:out value="${actionBean.book.remark}"/> </td> </tr> </table> </body> </html>
The showOneBook.jsp
displays one book, which we have found by its ID.
The Book bean
The Book
bean is a Java class that represents a domain object
of our application—a book.
package com.zetcode.bean; public class Book { private Long id; private String author; private String title; private int yearPublished; private String remark; public Book() {}; public Book(String author, String title, int published, String remark) { this.author = author; this.title = title; this.yearPublished = published; this.remark = remark; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getPublished() { return yearPublished; } public void setPublished(int published) { this.yearPublished = published; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } }
The bean has the necessary attributes and getter and setter methods. Note that it is also necessary to add an empty constructor.
Action beans
Stripes' ActionBean
is an object that receives data submitted in requests and processes
the user's input. It both defines the properties of the form and the processing logic for the form.
In the end it returns a view to the user. In our application, we have three action beans:
AddBookActionBean
, SelectAllBooksActionBean
, and SelectOneBookActionBean
.
Each of them represents some action to be taken in the application.

We place the action beans into the com.zetcode.action
package.
package com.zetcode.action; import com.zetcode.bean.Book; import com.zetcode.service.BookService; import net.sourceforge.stripes.action.ActionBean; import net.sourceforge.stripes.action.ActionBeanContext; import net.sourceforge.stripes.action.DefaultHandler; import net.sourceforge.stripes.action.ForwardResolution; import net.sourceforge.stripes.action.Resolution; import net.sourceforge.stripes.validation.Validate; public class AddBookActionBean implements ActionBean { private static final String VIEW = "/bookAdded.jsp"; private ActionBeanContext context; @Validate(required = true) private String author; @Validate(required = true) private String title; @Validate(required = true) private int yearPublished; @Validate(required = true) private String remark; public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getYearPublished() { return yearPublished; } public void setYearPublished(int yearPublished) { this.yearPublished = yearPublished; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } @DefaultHandler public Resolution addBook() { Book book = new Book(this.author, this.title, this.yearPublished, this.remark); BookService.saveBook(book); return new ForwardResolution(VIEW); } @Override public void setContext(ActionBeanContext context) { this.context = context; } @Override public ActionBeanContext getContext() { return context; } }
The AddBookActionBean
is called after we have filled in
the form to add a new book. The action bean automatically binds the request attributes
to its own attributes.
private static final String VIEW = "/bookAdded.jsp";
The AddBookActionBean
returns bookAdded.jsp
page when the
book is successfully saved to the database.
@Validate(required=true) private String author; @Validate(required=true) private String title; ...
With the @Validate
annotation, we provide validation services to
our HTML fields. The fields must not be empty and must match the correct data type.

The Submit action fails if the year of publishing has a non-integer character.
@DefaultHandler public Resolution addBook() { Book book = new Book(this.author, this.title, this.yearPublished, this.remark); BookService.saveBook(book); return new ForwardResolution(VIEW); }
The @DefaultHandler
annotation specifies the default handler
method for this action bean. (It is possible to define several handlers.)
The handler creates the Book
bean, calls the BookService.saveBook()
and forwards to the appropriate view.
package com.zetcode.action; import com.zetcode.bean.Book; import com.zetcode.service.BookService; import java.io.IOException; import net.sourceforge.stripes.action.ActionBean; import net.sourceforge.stripes.action.ActionBeanContext; import net.sourceforge.stripes.action.DefaultHandler; import net.sourceforge.stripes.action.ForwardResolution; import net.sourceforge.stripes.action.Resolution; import net.sourceforge.stripes.validation.Validate; public class SelectOneBookActionBean implements ActionBean { private static final String VIEW = "/showOneBook.jsp"; private ActionBeanContext context; private Book book; @Validate(required=true) private Long bookId; public Book getBook() { return book; } public void setBook(Book book) { this.book = book; } public Long getBookId() { return bookId; } public void setBookId(Long bookId) { this.bookId = bookId; } @DefaultHandler public Resolution showOneBook() throws IOException { this.book = BookService.getBook(bookId); return new ForwardResolution(VIEW); } @Override public void setContext(ActionBeanContext context) { this.context = context; } @Override public ActionBeanContext getContext() { return context; } }
The SelectOneBookActionBean
is called after we have
clicked on the Submit button in the findBook.jsp
.
@DefaultHandler public Resolution showOneBook() throws IOException { this.book = BookService.getBook(bookId); return new ForwardResolution(VIEW); }
The default handler calls the BookService.getBook()
method and forwards then to the view.
package com.zetcode.action; import com.zetcode.bean.Book; import com.zetcode.service.BookService; import java.util.List; import net.sourceforge.stripes.action.ActionBean; import net.sourceforge.stripes.action.ActionBeanContext; import net.sourceforge.stripes.action.DefaultHandler; import net.sourceforge.stripes.action.ForwardResolution; import net.sourceforge.stripes.action.Resolution; public class SelectAllBooksActionBean implements ActionBean { private static final String VIEW = "/showAllBooks.jsp"; private ActionBeanContext context; private List<Book> books; public List<Book> getBooks() { return books; } public void setBooks(List<Book> books) { this.books = books; } @DefaultHandler public Resolution showAll() { this.books = BookService.getAllBooks(); return new ForwardResolution(VIEW); } @Override public void setContext(ActionBeanContext context) { this.context = context; } @Override public ActionBeanContext getContext() { return context; } }
The SelectAllBooksActionBean
is responsible for
selecting all books from the database.
@DefaultHandler public Resolution showAll() { this.books = BookService.getAllBooks(); return new ForwardResolution(VIEW); }
The BookService.getAllBooks()
is called to
do the job.
Services
The BookService
contains method to communicate
with the database.
package com.zetcode.service; import com.zetcode.bean.Book; import com.zetcode.persistence.MyBatisDAO; import java.util.List; public class BookService { public static void saveBook(Book book) { MyBatisDAO mbd = new MyBatisDAO(); mbd.saveBook(book); } public static List<Book> getAllBooks() { MyBatisDAO mbd = new MyBatisDAO(); List<Book> books = mbd.findAll(); return books; } public static Book getBook(Long id) { MyBatisDAO mbd = new MyBatisDAO(); Book book = mbd.findBook(id); return book; } }
The DAO pattern is used to make the example more portable.
public static List<Book> getAllBooks() { MyBatisDAO mbd = new MyBatisDAO(); List<Book> books = mbd.findAll(); return books; }
The getAllBooks()
method creates the MyBatisDAO
and calls its findAll()
method. It returns a list of retrieved books.
DAO
The Data Access Object (DAO) pattern is used to separate low level data accessing API or operations from high level business services.
package com.zetcode.persistence; import com.zetcode.bean.Book; import java.util.List; public interface BookDAO { public void saveBook(Book book); public Book findBook(Long id); public List<Book> findAll(); }
The methods to access the data are defined in the BookDAO
interface. The code is less coupled when we program against this interface.
package com.zetcode.persistence; import com.zetcode.bean.Book; import com.zetcode.util.ServiceLocator; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; public class MyBatisDAO implements BookDAO { @Override public void saveBook(Book book) { SqlSession session = null; try { SqlSessionFactory factory = ServiceLocator.getSessionFactory(); session = factory.openSession(); session.insert("insertBook", book); session.commit(); } finally { if (session != null) { session.close(); } } } @Override public Book findBook(Long id) { SqlSession session = null; Book book = null; try { SqlSessionFactory factory = ServiceLocator.getSessionFactory(); session = factory.openSession(); book = session.selectOne("selectBook", id); } finally { if (session != null) { session.close(); } } return book; } @Override public List<Book> findAll() { SqlSession session = null; List<Book> retrieveList = null; try { SqlSessionFactory factory = ServiceLocator.getSessionFactory(); session = factory.openSession(); retrieveList = session.selectList("selectAllBooks"); } finally { if (session != null) { session.close(); } } return retrieveList; } }
The MyBatisDAO
is a concrete implementation of the BookDAO
interface. If the underlying data source changes, we can easily switch to a new
DAO implementation.
@Override public void saveBook(Book book) { SqlSession session = null; try { SqlSessionFactory factory = ServiceLocator.getSessionFactory(); session = factory.openSession(); session.insert("insertBook", book); session.commit(); } finally { if (session != null) { session.close(); } } }
The saveBook()
method saves a new book into the database.
An SqlSessionFactory
is created to produce an SqlSession
,
which is the primary Java interface for working with MyBatis. The creation of
the factory is delegated to the ServiceLocator
.
The session's insert()
method executes an insert statement with the
given parameter object. The commit()
method commits the changes
to the database.
SqlSessionFactory factory = ServiceLocator.getSessionFactory(); session = factory.openSession(); book = session.selectOne("selectBook", id);
For the selection of a single book, we pass the id
parameter
to the session's selectOne()
method.
SqlSessionFactory factory = ServiceLocator.getSessionFactory(); session = factory.openSession(); retrieveList = session.selectList("selectAllBooks");
The selectList()
method returns a list of book objects.
package com.zetcode.util; import java.io.IOException; import java.io.InputStream; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class ServiceLocator { public static SqlSessionFactory getSessionFactory() { InputStream inputStream = null; SqlSessionFactory sqlSessionFactory = null; try { String resource = "mybatis-config.xml"; inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException ex) { Logger.getLogger(ServiceLocator.class.getName()).log(Level.SEVERE, null, ex); } finally { try { if (inputStream != null) { inputStream.close(); } } catch (IOException ex) { Logger.getLogger(ServiceLocator.class.getName()).log(Level.WARNING, null, ex); } } return sqlSessionFactory; } }
The ServiceLocator
builds the SqlSessionFactory
from the
supplied configuration file. The factory is later used to produce an SqlSession
,
which is the primary interface to communicate with MyBatis.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <typeAlias alias="Book" type="com.zetcode.bean.Book"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="org.apache.derby.jdbc.ClientDriver"/> <property name="url" value="jdbc:derby://localhost:1527/books"/> <property name="username" value="app"/> <property name="password" value="app"/> </dataSource> </environment> </environments> <mappers> <mapper resource="BookMapper.xml"/> </mappers> </configuration>
In the mybatis-config.xml
file, we create a new book Book
type,
define the data source for Derby, and specify the mapper file.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zetcode"> <select id="selectAllBooks" resultType="Book"> SELECT * FROM Books </select> <select id="selectBook" parameterType="long" resultType="Book"> SELECT * FROM Books WHERE Id = #{id} </select> <insert id="insertBook" parameterType="Book" statementType="PREPARED"> INSERT INTO Books(Author, Title, Published, Remark) VALUES (#{author}, #{title}, #{published}, #{remark}) </insert> </mapper>
In the BookMapper.xml
we have the SQL commands used in our
application. It has two select and one insert commands.
<select id="selectAllBooks" resultType="Book"> SELECT * FROM Books </select>
Notice that for the result type, we do not define a collection but the type of the collection items.

The screenshot shows all books selected from a sample database.
In this tutorial, we have created a web application with Stripes, MyBatis, and Derby. We have used a three layer and DAO software patterns. NetBeans was used to build the application.
List all Java tutorials.