{"id":2223,"date":"2010-05-05T15:27:51","date_gmt":"2010-05-05T13:27:51","guid":{"rendered":"http:\/\/blog.jteam.nl\/?p=2223"},"modified":"2010-05-05T15:27:51","modified_gmt":"2010-05-05T13:27:51","slug":"implementing-rss-feeds-with-new-features-of-spring-3","status":"publish","type":"post","link":"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/","title":{"rendered":"Implementing RSS Feeds with new features of Spring 3"},"content":{"rendered":"<p>In this post I explain how we implemented the way we created the RSS feeds in a project and the challenges that we had during the set-up.<\/p>\n<p>My colleague Jettro Coenradie explained in a previous <a href=\"http:\/\/www.gridshore.nl\/2010\/02\/16\/creating-a-w3c-validated-rss-feed-using-rome-and-spring-3\/\" target=\"_blank\" rel=\"noopener\">post<\/a> how you can create a feed using Rome and Spring 3, but didn\u2019t elaborated on the Spring 3 part. I will explain how we used Spring 3 to create the feeds.<\/p>\n<p><!--more--><\/p>\n<h2>Context<\/h2>\n<p>In this project we need to support a large number of different feeds. As an example I will use the news feed that we need to create for different subjects. The subjects are created in a CMS and therefore people can add subjects whenever they want. This means that we want to support dynamically created feeds.<\/p>\n<h2>Controller<\/h2>\n<p>The controller is the place where the request mapping takes place.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\n@Controller\npublic class SubjectRssController extends AbstractRssController {\n\n    @SessionManagedDaos\n    @RequestMapping(value = &quot;\/subjects\/{subjectName}\/news.rss&quot;, method = RequestMethod.GET)\n    public String generateSubjectNewsFeedItems(ModelMap modelMap, @PathVariable final String subjectName,\n                                               HttpServletRequest request, RssSubjectDao subjectDao) throws ServletException {\n        SubjectBean subject = findSubject(subjectName, request, subjectDao);\n\n        RssQueryResultMapper mapper = getSubjectQueryResultMapper();\n        List&lt;item&gt; items = subjectDao.findNewsForSubject(subject, mapper);\n\n        modelMap.addAttribute(&quot;items&quot;, items);\n        modelMap.addAttribute(&quot;subjectName&quot;, subject.getTitle());\n        return &quot;subjectRssFeed&quot;;\n}\n<\/pre>\n<h3>Annotations<\/h3>\n<p>The first thing you might notice when you look at the code above are the two annotations (@SessionManagedDaos and @RequestMapping) on the method. The @SessionManagedDaos is an annotation that is created by us. This annotation manages the session that we use from the CMS connection pool.<\/p>\n<p>The second annotation is the @RequestMapping. This annotation has the value <em>&#8220;\/subjects\/{subjectName}\/news.rss&#8221; <\/em>which means that every path that matches this pattern will be mapped to this method. In this pattern uses a new feature of Spring 3, namely the variable in the path. The @PathVariable annotation in front of the parameter <em>subjectName <\/em>indicates that the variable in the path needs to be bound to the method parameter.<\/p>\n<p>This helps us to support any request with a given subject name and therefore we do not need to change the code if a new subject is created.<\/p>\n<h3>Wrong request<\/h3>\n<p>With the freedom of the path pattern also comes the problem that a person can try any subject name that he wants. In order to prevent that we execute a query for a subject that does not exist, we execute a query that finds the subject. If the subject is not found, we throw a NoSuchRequestHandlingMethodException. This exception is handled by the DefaultHandlerExceptionResolver. This resolver handles certain standard Spring MVC exceptions by setting a specific response status code. In our case the status code will be a 404.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\nprotected SubjectBean findSubject(String subjectName, HttpServletRequest request, RssSubjectDao subjectDao)\n                                  throws NoSuchRequestHandlingMethodException {\n    SubjectBean subject = subjectDao.findSubjectBeanByName(subjectName);\n    if (subject == null) {\n        throw new NoSuchRequestHandlingMethodException(request);\n    }\n\n    return subject;\n}\n<\/pre>\n<h3>Items<\/h3>\n<p>The implementation of the controller is not special. We execute a query that finds some news and with the help of a mapper, we map the retrieved beans to RSS <a href=\"https:\/\/rome.dev.java.net\/apidocs\/0_3\/com\/sun\/syndication\/feed\/rss\/Item.html\" target=\"_blank\" rel=\"noopener\">items<\/a>. These items, as well as the subject title, are added to the model.<\/p>\n<h2>View<\/h2>\n<p>Now that our model is filled, we can create the view. Spring 3 provides us with the <a href=\"http:\/\/static.springsource.org\/spring\/docs\/3.0.x\/javadoc-api\/org\/springframework\/web\/servlet\/view\/feed\/AbstractRssFeedView.html\" target=\"_blank\" rel=\"noopener\">AbstractRssFeedView<\/a>. This view has a few entry points to create the feed.<\/p>\n<p>We created a BaseRssFeedView which extends the AbstractRssFeedView. The BaseRssFeedView overrides three methods that build the feed.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npublic abstract class BaseRssFeedView extends AbstractRssFeedView {\n\n    private LocalizedMessageResolver messages;\n\n    @Override\n    protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {\n        super.prepareResponse(request, response);\n       response.setCharacterEncoding(CharacterEncodingConstants.UTF8);\n    }\n\n    @Override\n    protected void buildFeedMetadata(Map&lt;String, Object&gt; model, Channel feed, HttpServletRequest request) {\n        RssMetaData rssMetaData = new RssMetaData();\n        configureRssMetaData(rssMetaData, model);\n\n        feed.setTitle(rssMetaData.getFeedTitle());\n        feed.setDescription(rssMetaData.getFeedDescription());\n        feed.setLink(feedLink);\n        feed.setWebMaster(feedWebmaster);\n        feed.setLanguage(feedLanguage);\n        feed.setCopyright(feedCopyright);\n\n        Image image = resolveImage(rssMetaData.getFeedTitle());\n        feed.setImage(image);\n        feed.setLastBuildDate(new Date());\n        feed.setTtl(TIME_TO_LIVE);\n\n        AtomNSModule module = new AtomNSModuleImpl();\n        module.setLink(rssMetaData.getFeedUrl());\n        feed.getModules().add(module);\n    }\n\n    @Override\n    protected List&lt;Item&gt; buildFeedItems(Map&lt;String, Object&gt; stringObjectMap, HttpServletRequest request, HttpServletResponse response) {\n        return (List&lt;Item&gt;) stringObjectMap.get(&quot;items&quot;);\n    }\n\n    protected abstract void configureRssMetaData(RssMetaData metaData, Map&lt;String, Object&gt; viewModel);\n}\n<\/pre>\n<p>I don\u2019t want to discuss the implementation of the methods, as I think that they are pretty self-explanatory. But I do want to discuss the one abstract method that needs to be implemented by the subclasses. This method allows the subclass to specify the specific metadata for the feed. The code below shows the view that would belong to our SubjectRssController.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\n@Component(&quot;subjectRssFeed&quot;)\npublic class SubjectRssFeedView extends BaseRssFeedView {\n\n    @Override\n    protected void configureRssMetaData(RssMetaData metaData, Map&lt;String, Object&gt; viewModel) {\n        String subjectName = (String) viewModel.get(&quot;subjectName&quot;);\n\n        LocalizedMessageResolver messages = getMessageResolver();\n        metaData.setFeedUrl(messages.getMessage(&quot;subject.news.rss.feed.url&quot;, subjectName));\n        metaData.setFeedTitle(messages.getMessage(&quot;subject.news.rss.feed.title&quot;, subjectName));\n        metaData.setFeedDescription(messages.getMessage(&quot;subject.news.rss.feed.description&quot;, subjectName));\n    }\n}\n<\/pre>\n<p>The class is annotated with @Component(&#8220;subjectRssFeed&#8221;). The name of the view is <em>subjectRssFeed<\/em> and needs to match with the view name you return in the controller.<\/p>\n<h3>Properties<\/h3>\n<p>In this case we assume that every subject has the same message for the specific metadata. So the only thing that differs is the subject name. For example, the description of a feed of the subject cars could be: <em>This feed contains the news items of the subject cars. <\/em><\/p>\n<p>So this means that we need to parameterize the messages. In order to do that we have created a class that resolves the message for us from the correct property file. This way we can still use the templates in the property files.<\/p>\n<p><em>subject.news.rss.feed.description=This feed contains the news items of the subject {0}<\/em><\/p>\n<p>Spring 3 also lets you annotate a field or method\/constructor parameter that indicates a default value expression for the affected argument. This means you could inject a property like this:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\n@Value(&quot;#{rssProperties.getProperty('subject.news.rss.feed.url')}&quot;)\npublic void setFeedUrl(String feedUrl) {\n    this.feedUrl = feedUrl;\n}\n<\/pre>\n<p>or<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\n@Value(&quot;#{rssProperties.getProperty('subject.news.rss.feed.url')}&quot;)\nprivate String feedUrl;\n<\/pre>\n<h2>Conclusion<\/h2>\n<p>I hope you got an idea of how Spring 3 can help you with creating RSS feeds. In our case it was really useful as we get all the advantages of Spring MVC and added new feeds are a piece of cake!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post I explain how we implemented the way we created the RSS feeds in a project and the challenges that we had during the set-up. My colleague Jettro Coenradie explained in a previous post how you can create a feed using Rome and Spring 3, but didn\u2019t elaborated on the Spring 3 part. [&hellip;]<\/p>\n","protected":false},"author":102,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","footnotes":""},"categories":[10],"tags":[200,11,9,181,182,201,95],"class_list":["post-2223","post","type-post","status-publish","format-standard","hentry","category-development","tag-feed","tag-java","tag-open-source","tag-rome","tag-rss","tag-spring-3","tag-spring-framework"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Implementing RSS Feeds with new features of Spring 3 - Trifork Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Implementing RSS Feeds with new features of Spring 3 - Trifork Blog\" \/>\n<meta property=\"og:description\" content=\"In this post I explain how we implemented the way we created the RSS feeds in a project and the challenges that we had during the set-up. My colleague Jettro Coenradie explained in a previous post how you can create a feed using Rome and Spring 3, but didn\u2019t elaborated on the Spring 3 part. [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/\" \/>\n<meta property=\"og:site_name\" content=\"Trifork Blog\" \/>\n<meta property=\"article:published_time\" content=\"2010-05-05T13:27:51+00:00\" \/>\n<meta name=\"author\" content=\"Roberto van der Linden\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Roberto van der Linden\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/\",\"url\":\"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/\",\"name\":\"Implementing RSS Feeds with new features of Spring 3 - Trifork Blog\",\"isPartOf\":{\"@id\":\"https:\/\/trifork.nl\/blog\/#website\"},\"datePublished\":\"2010-05-05T13:27:51+00:00\",\"author\":{\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/037974cf3e24a7b09a93770b190d6e35\"},\"breadcrumb\":{\"@id\":\"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/trifork.nl\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Implementing RSS Feeds with new features of Spring 3\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/trifork.nl\/blog\/#website\",\"url\":\"https:\/\/trifork.nl\/blog\/\",\"name\":\"Trifork Blog\",\"description\":\"Keep updated on the technical solutions Trifork is working on!\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/trifork.nl\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/037974cf3e24a7b09a93770b190d6e35\",\"name\":\"Roberto van der Linden\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/trifork.nl\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/afe49faf7ef8dd3753baefb334568b10?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/afe49faf7ef8dd3753baefb334568b10?s=96&d=mm&r=g\",\"caption\":\"Roberto van der Linden\"},\"url\":\"https:\/\/trifork.nl\/blog\/author\/roberto\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Implementing RSS Feeds with new features of Spring 3 - Trifork Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/","og_locale":"en_US","og_type":"article","og_title":"Implementing RSS Feeds with new features of Spring 3 - Trifork Blog","og_description":"In this post I explain how we implemented the way we created the RSS feeds in a project and the challenges that we had during the set-up. My colleague Jettro Coenradie explained in a previous post how you can create a feed using Rome and Spring 3, but didn\u2019t elaborated on the Spring 3 part. [&hellip;]","og_url":"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/","og_site_name":"Trifork Blog","article_published_time":"2010-05-05T13:27:51+00:00","author":"Roberto van der Linden","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Roberto van der Linden","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/","url":"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/","name":"Implementing RSS Feeds with new features of Spring 3 - Trifork Blog","isPartOf":{"@id":"https:\/\/trifork.nl\/blog\/#website"},"datePublished":"2010-05-05T13:27:51+00:00","author":{"@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/037974cf3e24a7b09a93770b190d6e35"},"breadcrumb":{"@id":"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/trifork.nl\/blog\/implementing-rss-feeds-with-new-features-of-spring-3\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/trifork.nl\/blog\/"},{"@type":"ListItem","position":2,"name":"Implementing RSS Feeds with new features of Spring 3"}]},{"@type":"WebSite","@id":"https:\/\/trifork.nl\/blog\/#website","url":"https:\/\/trifork.nl\/blog\/","name":"Trifork Blog","description":"Keep updated on the technical solutions Trifork is working on!","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/trifork.nl\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/037974cf3e24a7b09a93770b190d6e35","name":"Roberto van der Linden","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/trifork.nl\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/afe49faf7ef8dd3753baefb334568b10?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/afe49faf7ef8dd3753baefb334568b10?s=96&d=mm&r=g","caption":"Roberto van der Linden"},"url":"https:\/\/trifork.nl\/blog\/author\/roberto\/"}]}},"_links":{"self":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts\/2223","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/users\/102"}],"replies":[{"embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/comments?post=2223"}],"version-history":[{"count":0,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/posts\/2223\/revisions"}],"wp:attachment":[{"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/media?parent=2223"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/categories?post=2223"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/trifork.nl\/blog\/wp-json\/wp\/v2\/tags?post=2223"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}