Now we come to the meat of the subject. Here we're going to implement a
Spring Web MVC view by extending Spring 3.0's new AbstractRssFeedView class
and by using ROME to model our news feed. Once we have the view in place, we'll
be ready to configure the mapping from the logical view name we set in the
controller to the view.
Listing 2 shows what's involved in implementing a view for an RSS feed. If
you're doing an Atom feed, the approach is entirely analogous, but you would
just need to extend AbstractAtomFeedView instead of
AbstractRssFeedView.
package rssdemo.web;
import java.util.*;
import javax.servlet.http.*;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.web.servlet.view.feed.AbstractRssFeedView;
import com.sun.syndication.feed.rss.Channel;
import com.sun.syndication.feed.rss.Description;
import com.sun.syndication.feed.rss.Item;
import rssdemo.model.NewsItem;
public final class RssNewsFeedView extends AbstractRssFeedView { // 1
private String feedTitle; // 2
private String feedDesc;
private String feedLink;
@Required
public void setFeedTitle(String feedTitle) {
this.feedTitle = feedTitle;
}
@Required
public void setFeedDescription(String feedDesc) {
this.feedDesc = feedDesc;
}
@Required
public void setFeedLink(String feedLink) {
this.feedLink = feedLink;
}
@Override
protected void buildFeedMetadata(
Map model, Channel feed, HttpServletRequest request) { // 3
feed.setTitle(feedTitle);
feed.setDescription(feedDesc);
feed.setLink(feedLink);
}
@Override
protected List<Item> buildFeedItems(
Map model,
HttpServletRequest request,
HttpServletResponse response)
throws Exception { // 4
@SuppressWarnings("unchecked")
List<NewsItem> newsItems =
(List<NewsItem>) model.get("newsItemList"); // 5
List<Item> feedItems = new ArrayList<Item>();
for (NewsItem newsItem : newsItems) { // 6
Item feedItem = new Item();
feedItem.setTitle(newsItem.getTitle());
feedItem.setAuthor(newsItem.getAuthor());
feedItem.setPubDate(newsItem.getDatePublished());
Description desc = new Description();
desc.setType("text/html");
desc.setValue(newsItem.getDescription());
feedItem.setDescription(desc);
feedItem.setLink(newsItem.getLink());
feedItems.add(feedItem);
}
return feedItems;
}
}
So what's going on here? Well, we begin by extending the AbstractRssFeedView
class 1. Then we include some injected fields for feed
metadata 2. We use these in the optional buildFeedMetadata()
method 3. I say "optional" because the AbstractRssFeedView
provides a dummy implementation (actually, its superclass AbstractFeedView provides it).
The method we're required to implement is buildFeedItems()
4. Here's where we map our list of domain objects
(here, a list of NewsItem objects that are just something we cooked
up ourselves) to the ROME API, which provides a structure for modeling feeds.
We begin by grabbing the NewsItem list off the model (recall from
listing 1 that we placed the list on the model in the controller) 5.
Then we iterate over the NewsItem list, mapping each one to a ROME
Item 6.
That should be pretty straightforward-looking. And we're almost done. There's
just one part that remains, and that's establishing the mapping between the
logical view name we return from the controller and the RssNewsFeedView
that we just created. We do that in the application context.