Introduction
It goes without saying that obviously you have a ton of choices when it comes to what web framework you want to use when building a web application. The reason why I think frameworks like Rails became so popular so fast was due to the glut of Java frameworks that were simply trying to do too much or were overly complicated. I don't want a ton of XML configuration nor do I want to feel like I'm coding a Swing application. The bottom line is I really like Stripes so far and I've at least dabbled in a lot of other Java web frameworks (At the time of this writing, my other favorite is Grails.)

As a tribute to Stripes, today (9/22/07), was my very first day even taking a serious look at the framework (Thanks Brandon for recommending I look at Stripes.). I downloaded the example application and looked at the source code of the "Bugzooky" example app and all I could say was "Wow, why I did I take so long to look at this framework??" Within an hour I was taking the old Struts CRUD app on this site and converting it to a Stripes application. Now be honest, how many other frameworks can you learn most all the basics of in less than hour? I guarantee you aren't going to be up and running that quickly with anything somewhat serious (no HelloWorld) within an hour of looking at an example application from most of the other popular frameworks out there.

Since I am new to the framework and I want to get this example application up for others to look at, I'm not going to comment on the source code below. Actually, the nice thing is I bet you can easily see what's going on without any comments!

One of the things I find nice about the examples on this site is that they all use the same Employee CRUD example pages and page flow. This should give you a good appreciation for how the different frameworks handle the same business requirement - simple CRUD operations. This example just uses a dummy in-memory persistence store. I'll have the iBATIS and Spring intergration done in a followup lesson shortly. I'm not showing every file here - just enough that you'll get a gist of what's going on.
The Setup
Download the source code using the link above. The source comes with an ant build file. The build uses Tomcat (if you want the war built and deployed) and will require an environment variable of CATALINA_HOME to be set. (I think the later versions might use TOMCAT_HOME so just fix the build file if that's the case.) To build and deploy just type "ant" (of course you need ant installed.) Stripes also requires Java5 and Servlet spec 2.4/JSP2.0 (Tomcat5 or higher is fine). Once the war is deployed and tomcat is runinng, just go to the url http://localhost:8080/stripes-crud/.

You should see:

employees
Employee
A simple POJO (there is also a Department POJO)

public class Employee implements Serializable {
    private Integer employeeId;
    private Integer age;
    private String firstName;
    private String lastName;
    private Department department;
  

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }

    public Integer getEmployeeId() {
        return employeeId;
    }

    public void setEmployeeId(Integer employeeId) {
        this.employeeId = employeeId;
    }
    ...
EmployeeDaoService

public class EmployeeDaoService implements EmployeeService {
    private EmployeeDao dao = new EmployeeNoDBdao();

    public List<Employee> getAllEmployees() {
        return dao.getAllEmployees();
    }

    public void updateEmployee(Employee emp) {
        dao.update(emp);
    }

    public void deleteEmployee(Integer id) {
        dao.delete(id);
    }

    public Employee getEmployee(Integer id) {
        return dao.getEmployee(id);
    }

    public void insertEmployee(Employee emp) {
        dao.insert(emp);
    }
}
EmployeeActionBean
The heart of the application. Later, in the jsp forms, you'll see something like: <stripes:form action="/Employee.action">. Stripes uses a naming convention that if it sees "Employee" it will map that to "EmloyeeActionBean.java." (If you had /FooBar.action, it would map to FooBarActionBean.)

public class EmployeeActionBean extends BaseActionBean {
    private Log logger = LogFactory.getLog(this.getClass());
    private final static String EMPLOYEES_DISPLAY = "/Employee.action?employees=";
    private final static String EMPLOYEES = "/WEB-INF/jsp/employees.jsp";
    private final static String EMPLOYEE_FORM = "/WEB-INF/jsp/employeeForm.jsp";

    EmployeeService employeeService = new EmployeeDaoService();
    DepartmentService departmentService = new DepartmentDaoService();
    
    @ValidateNestedProperties({
        @Validate(field="firstName", required=true),
        @Validate(field="lastName", required=true),
        @Validate(field="age", required=true,converter=IntegerTypeConverter.class)
    })
    private Employee employee;

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

    @DontValidate
    @DefaultHandler
    public Resolution employees() {
        logger.debug("employees");
        return new ForwardResolution(EMPLOYEES);
    }

    //sets up our form for editing or inserting an Employee
    @DontValidate
    public Resolution preEdit() {
        if ( this.employee != null && this.employee.getEmployeeId() != null  ) {
            //we're setting up for an update so populate Employee
            this.employee = employeeService.getEmployee(this.employee.getEmployeeId());
            logger.debug("employee = "+employee);
        }   
        return new ForwardResolution(EMPLOYEE_FORM);
    }

    public Resolution save() {
        if ( this.employee.getEmployeeId() == null ) {
            logger.debug("adding employee: "+employee );
            employeeService.insertEmployee(employee);
        } else {
            logger.debug("updating employee: "+employee );
            employeeService.updateEmployee(employee);
        }
        return new RedirectResolution(EMPLOYEES_DISPLAY);
    }

    @DontValidate
    public Resolution delete() {
        logger.debug("deleting employee "+employee );
        employeeService.deleteEmployee(this.employee.getEmployeeId());
        return new RedirectResolution(EMPLOYEES_DISPLAY);
    }

    @DontValidate
    public Resolution cancel() {
        logger.debug("cancel");
        return new RedirectResolution(EMPLOYEES_DISPLAY);
    }

    public List getAllDepartments() {
        return departmentService.getAllDepartments();
    }
    public List getAllEmployees() {
        return employeeService.getAllEmployees();
    }
}
employees.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ include file="/taglibs.jsp" %>
<html>
<head>
    <link href="<c:url value='main.css'/>" rel="stylesheet" type="text/css"/>
    <title><fmt:message key="label.employees"/></title>
</head>
<body>
<div class="titleDiv"><stripes:label for="application.title"/></div>
<h1><fmt:message key="label.employees"/></h1>
<stripes:link href="/Employee.action" event="preEdit">Add New Employee</stripes:link>
<br/><br/>
<table class="borderAll">
    <tr>
        <th><stripes:label for="label.firstName"/></th>
        <th><stripes:label for="label.lastName"/></th>
        <th><stripes:label for="label.age"/></th>
        <th><stripes:label for="label.department"/></th>
        <th> </th>
    </tr>

    <c:forEach var="emp" items="${actionBean.allEmployees}" varStatus="loop">
        <tr class="${loop.index%2==0?'even':'odd'}">
            <td class="nowrap">${emp.firstName}</td>
            <td class="nowrap">${emp.lastName}</td>
            <td class="nowrap">${emp.age}</td>
            <td class="nowrap">${emp.department.name}</td>
            <td class="nowrap">
                <stripes:link href="/Employee.action" event="preEdit">
                <stripes:param name="employee.employeeId" value="${emp.employeeId}"/>Edit</stripes:link>
                   
                <stripes:link href="/Employee.action" event="delete">
                <stripes:param name="employee.employeeId" value="${emp.employeeId}"/>Delete</stripes:link>
            </td>
        </tr>
    </c:forEach>
    </table>
</body>
</html>
employeeForm.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ include file="/taglibs.jsp" %>
<c:set var="insertUpdateTitle" value="${empty actionBean.employee.employeeId ?'Add Employee':'Update Employee'}"/>
<html>
<head>
    <link href="<c:url value='main.css'/>" rel="stylesheet" type="text/css"/>
    <style>td { white-space:nowrap; }</style>
    <title>${insertUpdateTitle}</title>
</head>
<body>
<div class="titleDiv"><stripes:label for="application.title"/></div>
<h1>${insertUpdateTitle}</h1>

<stripes:form action="/Employee.action">
<stripes:errors/>
    <table>
         <tr>
            <td class="tdLabel"><stripes:label for="label.firstName"/>:</td>
            <td><stripes:text name="employee.firstName" size="40"/> </td>
        </tr>
        <tr>
            <td class="tdLabel"><stripes:label for="label.lastName"/>:</td>
            <td><stripes:text name="employee.lastName" size="40"/></td>
        </tr>
        <tr>
            <td class="tdLabel"><stripes:label for="label.age"/>:</td>
            <td><stripes:text name="employee.age" size="20"/></td>
        </tr>
         <tr>
            <td class="tdLabel"><stripes:label for="label.department"/>:</td>
            <td>
                <stripes:select name="employee.department.departmentId">
                    <stripes:options-collection collection="${actionBean.allDepartments}" label="name" value="departmentId"/>
                </stripes:select>
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <stripes:hidden name="employee.employeeId"/>
                <br/>
                <stripes:submit name="save" value="Save" class="butStnd"/>
                    
                <stripes:submit name="cancel" value="Cancel" class="butStnd"/>
            </td>
        </tr>
    </table>
</stripes:form>
</body>
</html>

Sample validation errors in employeeForm.jsp:

employees
web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
         http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">

    <description>
      Stripes CRUD Example
    </description>
    <display-name>Stripes CRUD Example</display-name>

    <filter>
        <description>
            Provides essential configuration and request processing services
            for the Stripes framework.
        </description>
        <display-name>Stripes Filter</display-name>
        <filter-name>StripesFilter</filter-name>
        <filter-class>net.sourceforge.stripes.controller.StripesFilter</filter-class>

        <!-- Optional init parameters for the Stripes Filter. -->
        <init-param>
            <param-name>ActionResolver.UrlFilters</param-name>
            <param-value>WEB-INF/classes</param-value>
        </init-param>
        <init-param>
            <param-name>ActionResolver.PackageFilters</param-name>
            <param-value>net.learntechnology.stripes.*</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>/dispatcher</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>StripesDispatcher</servlet-name>
        <url-pattern>/action/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>StripesDispatcher</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
        <param-value>StripesResources</param-value>
    </context-param>

</web-app>

Code and Lesson - Rick Reumann