Spring 4 MVC Atom and RSS Feed Example with ROME using JavaConfig
October 01, 2015
This page will walk through Spring 4 MVC Atom and RSS feed example with ROME using JavaConfig. Spring provides AbstractAtomFeedView and AbstractRssFeedView for Atom and RSS feed respectively. To generate Atom feed we need to define buildFeedMetadata() and buildFeedEntries() methods provided by AbstractAtomFeedView. To generate RSS feed we need to define buildFeedMetadata() and buildFeedItems() methods provided by AbstractRssFeedView. In JavaConfig, we will register our view classes using ViewResolverRegistry which will select proper view on user request for Atom and RSS feed. Find the complete example.
Differences between Atom and RSS Feed
1. Atom is called Atom Syndication Format whereas RSS is called Really Simple Syndication2. Atom feed can be HTML, XHTML, XML etc and RSS feed is plain TEXT or escaped HTML.
3. Atom feed can specify language for each entry whereas RSS feed can not specify language for each item.
4. The elements of Atom can be used in other XML whereas RSS are nor generally reusable in other XML.
Software Used
Find the software used in our demo.1. Java 7
2. Spring 4
3. ROME 1.5.1
4. Gradle
5. Eclipse
6. Tomcat 8
Project Structure in Eclipse
Find the project structure in eclipse.Gradle for Spring 4 and ROME API
Find the gradle build file for Spring and ROME API.build.gradle
apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'war' archivesBaseName = 'Spring4' version = '1' repositories { mavenCentral() } dependencies { compile 'org.springframework.boot:spring-boot-starter-web:1.2.3.RELEASE' compile 'com.rometools:rome:1.5.1' providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat:1.1.5.RELEASE' }
Atom Feed: Implement AbstractAtomFeedView
ContentAtomView.java
package com.concretepage.view; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.view.feed.AbstractAtomFeedView; import com.concretepage.bean.MyFeed; import com.rometools.rome.feed.atom.Content; import com.rometools.rome.feed.atom.Entry; import com.rometools.rome.feed.atom.Feed; import com.rometools.rome.feed.atom.Link; public class ContentAtomView extends AbstractAtomFeedView { @Override protected void buildFeedMetadata(Map<String, Object> model, Feed feed, HttpServletRequest request) { feed.setId("id1234"); feed.setTitle("Concretepage.com"); List<Link> links = new ArrayList<>(); Link link = new Link(); link.setHref("http://www.concretepage.com"); links.add(link); feed.setAlternateLinks(links); } @Override protected List<Entry> buildFeedEntries(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { List<Entry> entries = new ArrayList<Entry>(); Object ob = model.get("feeds"); if (ob instanceof List){ for(int i = 0; i < ((List<?>)ob).size(); i++){ Object feedObj = ((List<?>) ob).get(i); MyFeed myFeed = (MyFeed)feedObj; Entry entry = new Entry(); entry.setId(myFeed.getFeedId()); entry.setPublished(myFeed.getPubDate()); entry.setTitle(myFeed.getTitle()); List<Link> links = new ArrayList<>(); Link link = new Link(); link.setHref(myFeed.getLink()); links.add(link); entry.setAlternateLinks(links); Content content = new Content(); content.setValue(myFeed.getDescription()); entry.setSummary(content); entries.add(entry); } } return entries; } }
com.rometools.rome.feed.atom.Feed : ROME API which sets the Atom feed metadata. The setter methods in
Feed
are setId(), setTitle(), setAlternateLinks() etc.
AbstractAtomFeedView.buildFeedMetadata(): Method is overridden to declare Atom feed metadata.
Feed
is one of the arguments of this method. We will set metadata using setter methods of Feed
.
AbstractAtomFeedView.buildFeedEntries(): Using this method, we prepare the entries of Atoms feeds. Controller passes the feed content instance to it which is accepted by
Map<String, Object> model
parameter of this method.
com.rometools.rome.feed.atom.Entry : ROME API which creates one entry of Atom feeds. The setter methods of
Entry
are setId(), setPublished(), setTitle(), setSummary(), setAlternateLinks() etc.
RSS Feed: Implement AbstractRssFeedView
ContentRssView.java
package com.concretepage.view; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.view.feed.AbstractRssFeedView; import com.concretepage.bean.MyFeed; import com.rometools.rome.feed.rss.Channel; import com.rometools.rome.feed.rss.Content; import com.rometools.rome.feed.rss.Item; public class ContentRssView extends AbstractRssFeedView { @Override protected void buildFeedMetadata(Map<String, Object> model, Channel channel, HttpServletRequest request) { channel.setTitle("Concretepage.com"); channel.setLink("http://www.concretepage.com"); channel.setDescription("Concretepage.com is a java tutorial."); } @Override protected List<Item> buildFeedItems( Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { List<Item> items = new ArrayList<>(); Object ob = model.get("feeds"); if (ob instanceof List){ for(int i = 0; i < ((List<?>)ob).size(); i++){ Object feedObj = ((List<?>) ob).get(i); MyFeed myFeed = (MyFeed)feedObj; Item item = new Item(); item.setTitle(myFeed.getTitle()); item.setLink(myFeed.getLink()); item.setPubDate(myFeed.getPubDate()); Content content = new Content(); content.setValue(myFeed.getDescription()); item.setContent(content); items.add(item); } } return items; } }
com.rometools.rome.feed.rss.Channel : ROME API which sets the RSS feed metadata. The setter methods in
Channel
are setTitle(), setLink(), setDescription() etc.
AbstractRssFeedView.buildFeedMetadata(): Method is overridden to declare RSS feed metadata.
Channel
is one of the arguments of this method. We will set metadata using setter methods of Channel
.
AbstractRssFeedView.buildFeedItems(): Using this method, we prepare the items of RSS feeds. Controller passes the feed content instance to it which is accepted by
Map<String, Object> model
parameter of this method.
com.rometools.rome.feed.rss.Item : ROME API which creates one item of RSS feeds. The setter methods of
Item
are setTitle(), setLink(), setPubDate(), setContent() etc.
JavaConfig for ViewResolverRegistry
So far we have created two views, one for Atom feed and second for RSS feed. Now we will register these two views withViewResolverRegistry
which will identify the media type of user request and accordingly it will display Atom or RSS feed.
AppConfiguration.java
package com.concretepage.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import com.concretepage.view.ContentAtomView; import com.concretepage.view.ContentRssView; @Configuration @ComponentScan("com.concretepage") @EnableWebMvc public class AppConfiguration extends WebMvcConfigurerAdapter { @Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.enableContentNegotiation(new ContentAtomView(), new ContentRssView()); } }
Initializer.java
package com.concretepage.config; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration.Dynamic; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; public class Initializer implements WebApplicationInitializer { public void onStartup(ServletContext servletContext) throws ServletException { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(AppConfiguration.class); ctx.setServletContext(servletContext); Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx)); dynamic.addMapping("/"); dynamic.setLoadOnStartup(1); } }
AbstractAtomFeedView
implementation class and if URL is /feed.rss then the response will be generated by AbstractRssFeedView
Create Bean Class
MyFeed.java
package com.concretepage.bean; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.springframework.stereotype.Repository; @Repository public class MyFeed { private String feedId; private String title; private String description; private Date pubDate; private String link; public String getFeedId() { return feedId; } public void setFeedId(String feedId) { this.feedId = feedId; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Date getPubDate() { return pubDate; } public void setPubDate(Date pubDate) { this.pubDate = pubDate; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } public List<MyFeed> createFeed() { List<MyFeed> feeds = new ArrayList<>(); MyFeed feed1 = new MyFeed(); feed1.setFeedId("100"); feed1.setTitle("Title one"); feed1.setDescription("This is description one"); feed1.setLink("http://www.urlone.com"); feed1.setPubDate(new Date()); feeds.add(feed1); MyFeed feed2 = new MyFeed(); feed2.setFeedId("200"); feed2.setTitle("Title two"); feed2.setDescription("This is description two"); feed2.setLink("http://www.urltwo.com"); feed2.setPubDate(new Date()); feeds.add(feed2); return feeds; } }
Create Controller Class
FeedController.java
package com.concretepage.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; import com.concretepage.bean.MyFeed; @Controller public class FeedController { @Autowired private MyFeed myFeed; @RequestMapping(value="/feed.*", method=RequestMethod.GET) public ModelAndView getContent() { ModelAndView mav = new ModelAndView(); mav.addObject("feeds", myFeed.createFeed()); return mav; } }
Output
1. For Atom feed.<?xml version="1.0" encoding="UTF-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <title>Concretepage.com</title> <link rel="alternate" href="http://www.concretepage.com" /> <id>id1234</id> <entry> <title>Title one</title> <link rel="alternate" href="http://www.urlone.com" /> <id>100</id> <published>2015-10-01T04:42:06Z</published> <summary>This is description one</summary> </entry> <entry> <title>Title two</title> <link rel="alternate" href="http://www.urltwo.com" /> <id>200</id> <published>2015-10-01T04:42:06Z</published> <summary>This is description two</summary> </entry> </feed>
<?xml version="1.0" encoding="UTF-8"?> <rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"> <channel> <title>Concretepage.com</title> <link>http://www.concretepage.com</link> <description>Concretepage.com is a java tutorial.</description> <item> <title>Title one</title> <link>http://www.urlone.com</link> <content:encoded>This is description one</content:encoded> <pubDate>Thu, 01 Oct 2015 04:46:16 GMT</pubDate> </item> <item> <title>Title two</title> <link>http://www.urltwo.com</link> <content:encoded>This is description two</content:encoded> <pubDate>Thu, 01 Oct 2015 04:46:16 GMT</pubDate> </item> </channel> </rss>