使用 Spring Boot 开发一个订阅 RSS 源的应用程序

259 阅读5分钟

使用 Spring Boot 开发一个订阅 RSS 源的应用程序,可以通过以下步骤实现。我们将使用 Rome 库来解析 RSS 源,并使用 Spring Boot 的功能来创建一个定期检查 RSS 源的新条目的应用程序。

步骤 1:创建 Spring Boot 项目

可以使用 Spring Initializr 来生成一个新的 Spring Boot 项目。选择以下依赖:

  • Spring Web
  • Spring Data JPA
  • H2 Database (或其他数据库)
  • Spring Boot DevTools (可选)

步骤 2:添加依赖

pom.xml 文件中添加 Rome 库的依赖:

<dependency>
    <groupId>com.rometools</groupId>
    <artifactId>rome</artifactId>
    <version>1.16.0</version>
</dependency>

步骤 3:创建 RSS 解析服务

创建一个服务类来解析 RSS 源:

package com.example.rssreader.service;

import com.rometools.rome.feed.synd.SyndEntry;
import com.rometools.rome.feed.synd.SyndFeed;
import com.rometools.rome.io.SyndFeedInput;
import com.rometools.rome.io.XmlReader;
import org.springframework.stereotype.Service;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;

@Service
public class RssService {
    public List<SyndEntry> fetchRssFeed(String rssUrl) throws Exception {
        URL feedUrl = new URL(rssUrl);
        SyndFeedInput input = new SyndFeedInput();
        SyndFeed feed = input.build(new XmlReader(feedUrl));
        return feed.getEntries();
    }
}

步骤 4:创建 RSS 条目实体

创建一个实体类来表示 RSS 条目:

package com.example.rssreader.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class RssEntry {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String title;
    private String link;

    // Getters and setters
}

步骤 5:创建存储库接口

创建一个 JPA 存储库接口来管理 RSS 条目的持久化:

package com.example.rssreader.repository;

import com.example.rssreader.model.RssEntry;
import org.springframework.data.jpa.repository.JpaRepository;

public interface RssEntryRepository extends JpaRepository<RssEntry, Long> {
}

步骤 6:创建调度任务

创建一个调度任务来定期检查和更新 RSS 条目:

package com.example.rssreader.task;

import com.example.rssreader.model.RssEntry;
import com.example.rssreader.repository.RssEntryRepository;
import com.example.rssreader.service.RssService;
import com.rometools.rome.feed.synd.SyndEntry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class RssScheduler {
    @Autowired
    private RssService rssService;

    @Autowired
    private RssEntryRepository rssEntryRepository;

    @Scheduled(fixedRate = 3600000) // 每小时运行一次
    public void fetchAndSaveRssEntries() {
        try {
            String rssUrl = "https://hornydragon.blogspot.com/feeds/posts/default?alt=rss";
            List<SyndEntry> entries = rssService.fetchRssFeed(rssUrl);
            for (SyndEntry entry : entries) {
                RssEntry rssEntry = new RssEntry();
                rssEntry.setTitle(entry.getTitle());
                rssEntry.setLink(entry.getLink());
                rssEntryRepository.save(rssEntry);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

步骤 7:配置 Spring Boot 应用

application.properties 文件中配置 H2 数据库:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true

步骤 8:运行应用程序

确保你的主应用程序类上有 @EnableScheduling 注解以启用调度:

package com.example.rssreader;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class RssReaderApplication {
    public static void main(String[] args) {
        SpringApplication.run(RssReaderApplication.class, args);
    }
}

现在,你的应用程序将每小时检查一次指定的 RSS 源,并将新的条目保存到数据库中。可以根据需要调整调度频率和其他配置。

要从上个月的数据开始订阅 RSS 源,可以使用 Rome 库来解析 RSS 源并过滤出从上个月开始的条目。在 Spring Boot 应用中实现这一点,您需要以下步骤:

步骤 1:创建 Spring Boot 项目

可以使用 Spring Initializr 来生成一个新的 Spring Boot 项目。选择以下依赖:

  • Spring Web
  • Spring Data JPA
  • H2 Database (或其他数据库)
  • Spring Boot DevTools (可选)

步骤 2:添加依赖

pom.xml 文件中添加 Rome 库的依赖:

<dependency>
    <groupId>com.rometools</groupId>
    <artifactId>rome</artifactId>
    <version>1.16.0</version>
</dependency>

步骤 3:创建 RSS 解析服务

创建一个服务类来解析 RSS 源并过滤出从上个月开始的条目:

package com.example.rssreader.service;

import com.rometools.rome.feed.synd.SyndEntry;
import com.rometools.rome.feed.synd.SyndFeed;
import com.rometools.rome.io.SyndFeedInput;
import com.rometools.rome.io.XmlReader;
import org.springframework.stereotype.Service;

import java.net.URL;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class RssService {
    public List<SyndEntry> fetchRssFeed(String rssUrl) throws Exception {
        URL feedUrl = new URL(rssUrl);
        SyndFeedInput input = new SyndFeedInput();
        SyndFeed feed = input.build(new XmlReader(feedUrl));

        LocalDate oneMonthAgo = LocalDate.now().minusMonths(1);
        Date oneMonthAgoDate = Date.from(oneMonthAgo.atStartOfDay(ZoneId.systemDefault()).toInstant());

        List<SyndEntry> filteredEntries = new ArrayList<>();
        for (SyndEntry entry : feed.getEntries()) {
            if (entry.getPublishedDate().after(oneMonthAgoDate)) {
                filteredEntries.add(entry);
            }
        }
        return filteredEntries;
    }
}

步骤 4:创建 RSS 条目实体

创建一个实体类来表示 RSS 条目:

package com.example.rssreader.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class RssEntry {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String title;
    private String link;
    private Date publishedDate;

    // Getters and setters
}

步骤 5:创建存储库接口

创建一个 JPA 存储库接口来管理 RSS 条目的持久化:

package com.example.rssreader.repository;

import com.example.rssreader.model.RssEntry;
import org.springframework.data.jpa.repository.JpaRepository;

public interface RssEntryRepository extends JpaRepository<RssEntry, Long> {
}

步骤 6:创建调度任务

创建一个调度任务来定期检查和更新 RSS 条目:

package com.example.rssreader.task;

import com.example.rssreader.model.RssEntry;
import com.example.rssreader.repository.RssEntryRepository;
import com.example.rssreader.service.RssService;
import com.rometools.rome.feed.synd.SyndEntry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class RssScheduler {
    @Autowired
    private RssService rssService;

    @Autowired
    private RssEntryRepository rssEntryRepository;

    @Scheduled(fixedRate = 3600000) // 每小时运行一次
    public void fetchAndSaveRssEntries() {
        try {
            String rssUrl = "https://hornydragon.blogspot.com/feeds/posts/default?alt=rss";
            List<SyndEntry> entries = rssService.fetchRssFeed(rssUrl);
            for (SyndEntry entry : entries) {
                RssEntry rssEntry = new RssEntry();
                rssEntry.setTitle(entry.getTitle());
                rssEntry.setLink(entry.getLink());
                rssEntry.setPublishedDate(entry.getPublishedDate());
                rssEntryRepository.save(rssEntry);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

步骤 7:配置 Spring Boot 应用

application.properties 文件中配置 H2 数据库:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true

步骤 8:运行应用程序

确保你的主应用程序类上有 @EnableScheduling 注解以启用调度:

package com.example.rssreader;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class RssReaderApplication {
    public static void main(String[] args) {
        SpringApplication.run(RssReaderApplication.class, args);
    }
}

总结

通过上述步骤,您可以使用 Spring Boot 和 Rome 库开发一个订阅 RSS 源的应用程序,并从上个月的数据开始订阅。这个应用程序会定期检查 RSS 源的新条目,并将符合条件的条目保存到数据库中。

为了测试您的 RSS 订阅功能,可以使用 Spring Boot 的测试框架和一些测试库来编写单元测试。我们将使用 JUnit 和 Mockito 来编写和执行测试。

步骤 1:添加测试依赖

pom.xml 中添加必要的测试依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.rometools</groupId>
    <artifactId>rome</artifactId>
    <version>1.16.0</version>
    <scope>test</scope>
</dependency>

步骤 2:编写测试用例

编写一个测试类来测试 RssServiceRssScheduler。以下是一个示例:

package com.example.rssreader;

import com.example.rssreader.model.RssEntry;
import com.example.rssreader.repository.RssEntryRepository;
import com.example.rssreader.service.RssService;
import com.example.rssreader.task.RssScheduler;
import com.rometools.rome.feed.synd.SyndEntry;
import com.rometools.rome.feed.synd.SyndFeed;
import com.rometools.rome.io.SyndFeedInput;
import com.rometools.rome.io.XmlReader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.context.SpringBootTest;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
@SpringBootTest
public class RssReaderApplicationTests {

    @Mock
    private RssService rssService;

    @Mock
    private RssEntryRepository rssEntryRepository;

    @InjectMocks
    private RssScheduler rssScheduler;

    private List<SyndEntry> mockEntries;

    @BeforeEach
    public void setUp() {
        // 创建一个模拟的 SyndEntry 列表
        mockEntries = new ArrayList<>();
        SyndEntry entry1 = mock(SyndEntry.class);
        SyndEntry entry2 = mock(SyndEntry.class);
        
        when(entry1.getTitle()).thenReturn("Title 1");
        when(entry1.getLink()).thenReturn("http://example.com/1");
        when(entry1.getPublishedDate()).thenReturn(new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000)); // 昨天的日期

        when(entry2.getTitle()).thenReturn("Title 2");
        when(entry2.getLink()).thenReturn("http://example.com/2");
        when(entry2.getPublishedDate()).thenReturn(new Date(System.currentTimeMillis() - 2 * 24 * 60 * 60 * 1000)); // 前天的日期

        mockEntries.add(entry1);
        mockEntries.add(entry2);
    }

    @Test
    public void testFetchRssFeed() throws Exception {
        // 模拟 rssService.fetchRssFeed 方法
        when(rssService.fetchRssFeed(anyString())).thenReturn(mockEntries);

        // 调用 rssScheduler 的 fetchAndSaveRssEntries 方法
        rssScheduler.fetchAndSaveRssEntries();

        // 验证 rssEntryRepository.save 调用次数
        verify(rssEntryRepository, times(2)).save(any(RssEntry.class));
    }
}

解释

  1. 添加依赖

    • pom.xml 中添加测试依赖,包括 Spring Boot Test、Mockito 和 Rome。
  2. 编写测试类

    • 使用 @ExtendWith(MockitoExtension.class)@SpringBootTest 注解来设置测试环境。
    • 使用 @Mock 注解来模拟 RssServiceRssEntryRepository
    • 使用 @InjectMocks 注解来创建 RssScheduler 实例,并注入模拟的依赖。
    • setUp 方法中创建模拟的 SyndEntry 列表。
    • testFetchRssFeed 测试方法中,模拟 rssService.fetchRssFeed 方法,调用 rssScheduler.fetchAndSaveRssEntries 方法,并验证 rssEntryRepository.save 的调用次数。

运行测试

通过运行上述测试类,可以验证 RssSchedulerfetchAndSaveRssEntries 方法是否正确地从 RSS 源中获取条目并保存到数据库中。

这个示例展示了如何使用 Spring Boot 和 Mockito 来编写单元测试,以测试您的 RSS 订阅功能。通过这种方式,可以确保您的代码在各种场景下都能正常工作。