Looping on an attribute with Simple Tag

I want to display a list of movies in a JSP page. The first idea is about generating a table and looping on all the items in the list.

It would be nice to make the job of looping in a simple tag (that means, in Java) and let JSP to do what it is good at, presenting data on the screen.

We can easily do that, but we need to well coordinate the action between JSP page and the tag. The JSP passes to the simple tag the movies list, the tag loops on the list, putting for each iteration an attribute in the JSP context containing the data chunk that the JSP will display.

As often happens, an example should make it clearer.

The movie data are organized in a JavaBean:
package ch10;

public class Movie {
    private String title;
    private String director;

    public Movie(String title, String director) {
        this.title = title;
        this.director = director;
    }

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

    public String getTitle() {
        return title;
    }

    public void setDirector(String director) {
        this.director = director;
    }

    public String getDirector() {
        return director;
    }
}
A servlet creates a list of movies and puts it in a request attribute, before forwarding the control to a JSP page:
java.util.List<ch10.Movie> movies = new ArrayList<ch10.Movie>();
movies.add(new ch10.Movie("Sherlock Holmes", "Guy Ritchie"));
movies.add(new ch10.Movie("Play Time", "Jacques Tati"));
movies.add(new ch10.Movie("Léon", "Luc Besson"));
request.setAttribute("movies", movies);
We put the tag declaration in the same TLD that we have already used for the first two simple tag handlers we have written, and we write it to accept an attribute named movies. But let's firstly have a look to the JSP page:
<%@ taglib prefix="st" uri="simpleTags" %>
<"-- ... -->
<table>
    <st:simple5 movies="${movies}">
    <tr>
        <td>${movie.title}</td>
        <td>${movie.director}</td>
    </tr>
    </st:simple5>
</table>
We want to pass the list to the tag, and then we want to use in the body of the tag an attribute named "movie", actually a Movie object, to display all the data. What happened to the loop? We moved it in the tag implementation.

Here is the tag declaration we are going to add to our TLD file:
<tag>
    <description>looping on movies</description>
    <name>simple5</name>
    <tag-class>ch10.SimpleTagTest5</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
        <name>movies</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
</tag>
The tag has an attribute named movies, that is required and could be a runtime expression.

What we miss is just the simple tag itself:
package ch10;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class SimpleTagTest5 extends SimpleTagSupport {
    private List<Movie> movies;

    public void setMovies(List<Movie> movies) {
        this.movies = movies;
    }

    @Override
    public void doTag() throws JspException, IOException {
        Iterator<Movie> i = movies.iterator();
        while(i.hasNext()) {
            Movie movie = (Movie)i.next();
            getJspContext().setAttribute("movie", movie);
            getJspBody().invoke(null);
        }
    }
}
For any iteration, we create a movie attribute for the current movie in the JSP context, and then display the current JSP fragment. And all the magic is done.

Much more stuff on Simple tag handlers in chapter ten of Head First Servlet and JSP.

No comments:

Post a Comment