The template and element for displaying the list of friends are already written in Example 5.8, “Template for listing friends” and Example 5.9, “The Java code used to add friends”. All that needs to be done is to add the database functionality. We need to create a SQL query, execute it in the database and finally iterate over the resulting rows. Fortunately RIFE, again, provides a nice way to do all this. The easiest way to explain is by showing the code, the method display
in FriendManager
:
Example 7.6. Retrieving the friends list
public void display(DbRowProcessor processor) { Select select = new Select(getDatasource()); select .from("Friend") .fields(Friend.class) .orderBy("firstname"); // fetch every row in the resultset and forward the processing // of the data to the DisplayProcessor executeFetchAll(select, processor); }
This method, display
, is called from the element to retrieve all the friends and insert them into the template. The query is constructed using the Friend bean class, which means that we don't have to specify all the fields, it just uses all the bean properties.
After executing the query, we iterate over the result by calling the DbQueryManager
method fetch
until all the rows are processed. This is where the DbRowProcessor
object, that is passed in as an argument, comes in handy.
The row processor is a way to keep the database code separated from the element and output generation code. Our FriendManager doesn't know anything about the elements that use it, and the elements don't know anything about the database code. This kind of design is almost always desirable since it makes the application a lot easier to maintain and develop.
Writing a row processor is simple. We just need to extend DbRowProcessor
and implement the method processRow
. Since this processor won't be needed anywhere outside the display element, it can be implemented as an inner class in tutorial/friends/Display.java
:
Example 7.7. Our row processor
private class DisplayProcessor extends DbRowProcessor { private Template mTemplate = null; /** * The constructor requires a Template instance in which the retrieved * data will be filled in. * * @param template the Template in which the results will be display */ DisplayProcessor(Template template) { mTemplate = template; } public boolean processRow(ResultSet resultSet) throws SQLException { mTemplate.setValue("firstname", encodeHtml(resultSet.getString("firstname"))); mTemplate.setValue("lastname", encodeHtml(resultSet.getString("lastname"))); mTemplate.setValue("description", encodeHtml(resultSet.getString("description"))); mTemplate.setValue("url", encodeHtml(resultSet.getString("url"))); mTemplate.appendBlock("rows", "row"); return true; } }
The separation between database and HTML generation is very clear here. The only thing the row processor does is getting the different values from the result set and using them to fill in the template.
The only thing left to do in the element's processElement
method, is to create a manager and invoke display
with our row processor:
FriendManager manager = new FriendManager(); DisplayProcessor processor = new DisplayProcessor(template); manager.display(processor);