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.