personalweb

Archived
git clone git://git.wimdupont.com/personalweb.git
Log | Files | Refs | README | LICENSE

commit 4e5741a4218c5a3748413624bfe1070239836ec2
parent eb9984c0b3bb4279d020741041a7d959efcdc048
Author: Wim Dupont <wim@wimdupont.com>
Date:   Fri, 24 Feb 2023 00:47:48 +0100

fix rss - removed rome


Former-commit-id: 4413b056c571c0f1470dacabaa33256a668c45c7
Diffstat:
Mpom.xml | 14+-------------
Msrc/main/java/com/wimdupont/personalweb/controller/FeedController.java | 21++++++++++++++-------
Asrc/main/java/com/wimdupont/personalweb/model/rss/Channel.java | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/wimdupont/personalweb/model/rss/Item.java | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/wimdupont/personalweb/model/rss/RssFeed.java | 45+++++++++++++++++++++++++++++++++++++++++++++
Msrc/main/java/com/wimdupont/personalweb/service/RssFeedGenerator.java | 69+++++++++++++++++++++++++++++++++------------------------------------
Dsrc/main/java/com/wimdupont/personalweb/service/SyndFeedService.java | 25-------------------------
Dsrc/main/java/com/wimdupont/personalweb/util/DateUtil.java | 14--------------
8 files changed, 258 insertions(+), 95 deletions(-)

diff --git a/pom.xml b/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> - <version>3.0.1</version> + <version>3.0.2</version> </parent> <groupId>com.wimdupont</groupId> <artifactId>personalweb</artifactId> @@ -16,8 +16,6 @@ <properties> <java.version>17</java.version> <asciidoctorj.version>2.5.7</asciidoctorj.version> - <rome.version>1.0</rome.version> - <rome.rometools.version>1.18.0</rome.rometools.version> </properties> <dependencies> @@ -61,20 +59,10 @@ </exclusions> </dependency> <dependency> - <groupId>com.rometools</groupId> - <artifactId>rome</artifactId> - <version>${rome.rometools.version}</version> - </dependency> - <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency> <dependency> - <groupId>rome</groupId> - <artifactId>rome</artifactId> - <version>${rome.version}</version> - </dependency> - <dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> </dependency> diff --git a/src/main/java/com/wimdupont/personalweb/controller/FeedController.java b/src/main/java/com/wimdupont/personalweb/controller/FeedController.java @@ -1,23 +1,30 @@ package com.wimdupont.personalweb.controller; -import com.rometools.rome.feed.rss.Channel; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.wimdupont.personalweb.service.RssFeedGenerator; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; +import static org.springframework.http.MediaType.APPLICATION_XML_VALUE; + @Controller public class FeedController { - private final RssFeedGenerator rssFeed; + private final RssFeedGenerator rssFeedGenerator; - public FeedController(RssFeedGenerator rssFeed) { - this.rssFeed = rssFeed; + public FeedController(RssFeedGenerator rssFeedGenerator) { + this.rssFeedGenerator = rssFeedGenerator; } @GetMapping(path = "/rss.xml") - public @ResponseBody Channel getRss(Model model) { - return rssFeed.getChannel(); + @ResponseBody + public ResponseEntity<String> getRss() throws JsonProcessingException { + return ResponseEntity.ok() + .contentType(MediaType.parseMediaType(APPLICATION_XML_VALUE)) + .body(new XmlMapper().writeValueAsString(rssFeedGenerator.getRssFeed())); } } diff --git a/src/main/java/com/wimdupont/personalweb/model/rss/Channel.java b/src/main/java/com/wimdupont/personalweb/model/rss/Channel.java @@ -0,0 +1,84 @@ +package com.wimdupont.personalweb.model.rss; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +import java.util.List; + +@JacksonXmlRootElement(localName = "channel") +public record Channel( + @JacksonXmlProperty + String title, + @JacksonXmlProperty + String link, + @JacksonXmlProperty + String description, + @JacksonXmlProperty + String language, + @JacksonXmlProperty + String pubDate, + @JacksonXmlElementWrapper(useWrapping = false) + List<Item> item +) { + + + private Channel(Builder builder) { + this(builder.title, + builder.link, + builder.description, + builder.language, + builder.pubDate, + builder.item); + } + + public static final class Builder { + private @JacksonXmlProperty String title; + private @JacksonXmlProperty String link; + private @JacksonXmlProperty String description; + private @JacksonXmlProperty String language; + private @JacksonXmlProperty String pubDate; + private @JacksonXmlElementWrapper(useWrapping = false) List<Item> item; + + private Builder() { + } + + public static Builder newBuilder() { + return new Builder(); + } + + public Builder title(@JacksonXmlProperty String val) { + title = val; + return this; + } + + public Builder link(@JacksonXmlProperty String val) { + link = val; + return this; + } + + public Builder description(@JacksonXmlProperty String val) { + description = val; + return this; + } + + public Builder language(@JacksonXmlProperty String val) { + language = val; + return this; + } + + public Builder pubDate(@JacksonXmlProperty String val) { + pubDate = val; + return this; + } + + public Builder item(@JacksonXmlElementWrapper(useWrapping = false) List<Item> val) { + item = val; + return this; + } + + public Channel build() { + return new Channel(this); + } + } +} diff --git a/src/main/java/com/wimdupont/personalweb/model/rss/Item.java b/src/main/java/com/wimdupont/personalweb/model/rss/Item.java @@ -0,0 +1,81 @@ +package com.wimdupont.personalweb.model.rss; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +@JacksonXmlRootElement(localName = "item") +public record Item( + @JacksonXmlProperty + String title, + @JacksonXmlProperty + String description, + @JacksonXmlProperty + String link, + @JacksonXmlProperty + String author, + @JacksonXmlProperty + String pubDate, + @JacksonXmlProperty + String guid +) { + + + private Item(Builder builder) { + this(builder.title, + builder.description, + builder.link, + builder.author, + builder.pubDate, + builder.guid); + } + + public static final class Builder { + private @JacksonXmlProperty String title; + private @JacksonXmlProperty String description; + private @JacksonXmlProperty String link; + private @JacksonXmlProperty String author; + private @JacksonXmlProperty String pubDate; + private @JacksonXmlProperty String guid; + + private Builder() { + } + + public static Builder newBuilder() { + return new Builder(); + } + + public Builder title(@JacksonXmlProperty String val) { + title = val; + return this; + } + + public Builder description(@JacksonXmlProperty String val) { + description = val; + return this; + } + + public Builder link(@JacksonXmlProperty String val) { + link = val; + return this; + } + + public Builder author(@JacksonXmlProperty String val) { + author = val; + return this; + } + + public Builder pubDate(@JacksonXmlProperty String val) { + pubDate = val; + return this; + } + + public Builder guid(@JacksonXmlProperty String val) { + guid = val; + return this; + } + + public Item build() { + return new Item(this); + } + } +} diff --git a/src/main/java/com/wimdupont/personalweb/model/rss/RssFeed.java b/src/main/java/com/wimdupont/personalweb/model/rss/RssFeed.java @@ -0,0 +1,45 @@ +package com.wimdupont.personalweb.model.rss; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +@JacksonXmlRootElement(localName = "rss") +public record RssFeed( + @JacksonXmlProperty(localName = "channel") + Channel channel, + + @JacksonXmlProperty(isAttribute = true) + String version +) { + + private RssFeed(Builder builder) { + this(builder.channel, + builder.version); + } + + public static final class Builder { + private @JacksonXmlProperty(localName = "channel") Channel channel; + private @JacksonXmlProperty(isAttribute = true) String version; + + private Builder() { + } + + public static Builder newBuilder() { + return new Builder(); + } + + public Builder channel(@JacksonXmlProperty(localName = "channel") Channel val) { + channel = val; + return this; + } + + public Builder version(@JacksonXmlProperty(isAttribute = true) String val) { + version = val; + return this; + } + + public RssFeed build() { + return new RssFeed(this); + } + } +} diff --git a/src/main/java/com/wimdupont/personalweb/service/RssFeedGenerator.java b/src/main/java/com/wimdupont/personalweb/service/RssFeedGenerator.java @@ -1,9 +1,8 @@ package com.wimdupont.personalweb.service; -import com.rometools.rome.feed.rss.Channel; -import com.rometools.rome.feed.rss.Content; -import com.rometools.rome.feed.rss.Guid; -import com.rometools.rome.feed.rss.Item; +import com.wimdupont.personalweb.model.rss.Channel; +import com.wimdupont.personalweb.model.rss.Item; +import com.wimdupont.personalweb.model.rss.RssFeed; import com.wimdupont.personalweb.util.Constants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,10 +10,12 @@ import org.springframework.stereotype.Service; import java.io.File; import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; -import java.util.Date; import java.util.List; @Service @@ -22,29 +23,30 @@ public class RssFeedGenerator { private static final Logger LOG = LoggerFactory.getLogger(RssFeedGenerator.class); private final ArticleService articleService; - private Channel channel; + private RssFeed rssFeed; public RssFeedGenerator(ArticleService articleService) { this.articleService = articleService; } - public Channel getChannel() { - return channel; + public RssFeed getRssFeed() { + return rssFeed; } public void generate() { - Channel channel = new Channel(); + Channel channel = Channel.Builder.newBuilder() + .title("Wim Dupont") + .pubDate(LocalDateTime.now().toString()) + .link("https://wimdupont.com") + .description("Updates from Wim Dupont") + .language("en-US") + .item(getItems()) + .build(); - channel.setFeedType("rss_2.0"); - channel.setTitle("Wim Dupont"); - channel.setDescription("Updates from Wim Dupont"); - channel.setLink("https://wimdupont.com/rss.xml"); - channel.setUri("https://wimdupont.com/rss.xml"); - channel.setGenerator("Wim's Generatorâ„¢"); - channel.setPubDate(new Date()); - channel.setItems(getItems()); - - this.channel = channel; + this.rssFeed = RssFeed.Builder.newBuilder() + .version("2.0") + .channel(channel) + .build(); } private List<Item> getItems() { @@ -62,28 +64,23 @@ public class RssFeedGenerator { } String title = article.getName().replace(Constants.HTML_SUFFIX, ""); - Item item = genericItem(new Date(article.lastModified()), title); - item.setTitle(title); - Content content = new Content(); - content.setValue(articleString); - item.setContent(content); - items.add(item); + LocalDateTime pubDate = Instant.ofEpochMilli(article.lastModified()) + .atZone(ZoneId.systemDefault()).toLocalDateTime(); + items.add(buildItem(pubDate, title, articleString)); } } return items; } - private Item genericItem(Date postDate, String title) { + private Item buildItem(LocalDateTime postDate, String title, String content) { String url = String.format("https://wimdupont.com/blog/article/%s", title); - Item item = new Item(); - item.setAuthor("Wim Dupont"); - item.setLink(url); - item.setTitle(title); - item.setUri(url); - Guid guid = new Guid(); - guid.setValue(title + "-" + postDate.getTime()); - item.setGuid(guid); - item.setPubDate(postDate); - return item; + return Item.Builder.newBuilder() + .title(title) + .link(url) + .pubDate(postDate.toString()) + .guid(title + "-" + postDate) + .author("Wim Dupont") + .description(content) + .build(); } } diff --git a/src/main/java/com/wimdupont/personalweb/service/SyndFeedService.java b/src/main/java/com/wimdupont/personalweb/service/SyndFeedService.java @@ -1,25 +0,0 @@ -package com.wimdupont.personalweb.service; - -import com.rometools.rome.feed.synd.SyndFeed; -import com.rometools.rome.io.FeedException; -import com.rometools.rome.io.SyndFeedInput; -import org.springframework.stereotype.Service; -import org.xml.sax.InputSource; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -@Service -public class SyndFeedService { - - public SyndFeed getSyndFeedForUrl(String url) throws IOException, IllegalArgumentException, FeedException { - SyndFeed feed; - try (InputStream inputStream = new URL(url).openConnection().getInputStream()) { - InputSource source = new InputSource(inputStream); - SyndFeedInput input = new SyndFeedInput(); - feed = input.build(source); - } - return feed; - } -} diff --git a/src/main/java/com/wimdupont/personalweb/util/DateUtil.java b/src/main/java/com/wimdupont/personalweb/util/DateUtil.java @@ -1,14 +0,0 @@ -package com.wimdupont.personalweb.util; - -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.Date; - -public final class DateUtil { - private DateUtil() { - } - - public static LocalDateTime toLocalDateTime(Date date) { - return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); - } -}