Redditにスケジュールしやすくする

Redditへのスケジュール設定を簡単にする

1. 概要

この記事では、記事のスケジュールをはるかに簡単にすることを目的として、continue the case studyadd a new feature to the Reddit applicationについて説明します。

スケジュールUIですべての記事を手でゆっくり追加する代わりに、ユーザーはRedditに記事を投稿するお気に入りのサイトをいくつか持つことができます。 これを行うにはRSSを使用します。

2. Siteエンティティ

まず、サイトを表すエンティティを作成しましょう。

@Entity
public class Site {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private String url;

    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    private User user;
}

urlフィールドはthe RSS feed of the siteのURLを表すことに注意してください。

3. リポジトリとサービス

次に-新しいサイトエンティティで動作するリポジトリを作成します。

public interface SiteRepository extends JpaRepository {
    List findByUser(User user);
}

そしてサービス:

public interface ISiteService {

    List getSitesByUser(User user);

    void saveSite(Site site);

    Site findSiteById(Long siteId);

    void deleteSiteById(Long siteId);
}
@Service
public class SiteService implements ISiteService {

    @Autowired
    private SiteRepository repo;

    @Override
    public List getSitesByUser(User user) {
        return repo.findByUser(user);
    }

    @Override
    public void saveSite(Site site) {
        repo.save(site);
    }

    @Override
    public Site findSiteById(Long siteId) {
        return repo.findOne(siteId);
    }

    @Override
    public void deleteSiteById(Long siteId) {
        repo.delete(siteId);
    }
}

4. フィードからデータをロードする

では、ローマ図書館を使用してウェブサイトフィードから記事の詳細を読み込む方法を見てみましょう。

まず、ローマをpom.xmlに追加する必要があります。


    com.rometools
    rome
    1.5.0

そして、それを使用してサイトのフィードを解析します。

public List getArticlesFromSite(Long siteId) {
    Site site = repo.findOne(siteId);
    return getArticlesFromSite(site);
}

List getArticlesFromSite(Site site) {
    List entries;
    try {
        entries = getFeedEntries(site.getUrl());
    } catch (Exception e) {
        throw new FeedServerException("Error Occurred while parsing feed", e);
    }
    return parseFeed(entries);
}

private List getFeedEntries(String feedUrl)
  throws IllegalArgumentException, FeedException, IOException {
    URL url = new URL(feedUrl);
    SyndFeed feed = new SyndFeedInput().build(new XmlReader(url));
    return feed.getEntries();
}

private List parseFeed(List entries) {
    List articles = new ArrayList();
    for (SyndEntry entry : entries) {
        articles.add(new SiteArticle(
          entry.getTitle(), entry.getLink(), entry.getPublishedDate()));
    }
    return articles;
}

最後に、応答で使用する単純なDTOは次のとおりです。

public class SiteArticle {
    private String title;
    private String link;
    private Date publishDate;
}

5. 例外処理

フィードを解析するときに、解析ロジック全体をtry-catchブロックにラップし、例外(例外)の場合は、それをラップしてスローすることに注意してください。

その理由は単純です–we need to control the type of exception that gets thrown out of the parsing process –そのため、その例外を処理し、APIのクライアントに適切な応答を提供できます。

@ExceptionHandler({ FeedServerException.class })
public ResponseEntity handleFeed(RuntimeException ex, WebRequest request) {
    logger.error("500 Status Code", ex);
    String bodyOfResponse = ex.getLocalizedMessage();
    return new ResponseEntity(bodyOfResponse, new HttpHeaders(),
      HttpStatus.INTERNAL_SERVER_ERROR);
}




6. サイトページ

6.1. サイトを表示する

最初に、ログインしているユーザーに属するサイトのリストを表示する方法を確認します。

@RequestMapping(value = "/sites")
@ResponseBody
public List getSitesList() {
    return service.getSitesByUser(getCurrentUser());
}

そして、これは非常にシンプルなフロントエンドピースです。

Site NameFeed URLActions

6.2. 新しいサイトを追加する

次に、ユーザーが新しいお気に入りのサイトを作成する方法を見てみましょう。

@RequestMapping(value = "/sites", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public void addSite(Site site) {
    if (!service.isValidFeedUrl(site.getUrl())) {
        throw new FeedServerException("Invalid Feed Url");
    }
    site.setUser(getCurrentUser());
    service.saveSite(site);
}

そして、こちらも非常にシンプルなクライアント側です。

6.3. フィードの検証

新しいフィードの検証は少し高価な操作です。実際にフィードを取得して解析し、完全に検証する必要があります。 簡単なサービス方法は次のとおりです。

public boolean isValidFeedUrl(String feedUrl) {
    try {
        return getFeedEntries(feedUrl).size() > 0;
    } catch (Exception e) {
        return false;
    }
}

6.3. サイトを削除する

それでは、ユーザーがdelete a site from their list of favorite sitesを実行する方法を見てみましょう。

@RequestMapping(value = "/sites/{id}", method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.OK)
public void deleteSite(@PathVariable("id") Long id) {
    service.deleteSiteById(id);
}

そして、ここでも-非常に簡単な-サービスレベルの方法:

public void deleteSiteById(Long siteId) {
    repo.delete(siteId);
}

7. サイトからの投稿をスケジュールする

それでは、実際にこれらのサイトの使用を開始し、ユーザーが新しい投稿を手動でではなく、既存のサイトから記事を読み込んでRedditに送信するようにスケジュールできる基本的な方法を実装しましょう。

7.1. スケジューリングフォームの変更

クライアントサイトから始めて、既存のschedulePostForm.htmlを変更しましょう–以下を追加します。


      追加したことに注意してください:

      • ボタン–“Load from my Sites” –プロセスを開始します

      • ポップアップ–サイトとその記事のリストを表示します

      7.2. サイトをロードする

      ポップアップでのサイトの読み込みは、JavaScriptを少し使用すると比較的簡単です。

      $('#myModal').on('shown.bs.modal', function () {
          if($("#siteList").children().length > 0)
              return;
          $.get("sites", function(data){
              $.each(data, function( index, site ) {
                  $("#siteList").append('
    • '+site.name+'
    • ') }); }); });

      8. 統合テスト

      最後に、2つの異なるフィード形式でSiteServiceをテストしてみましょう。

      public class SiteIntegrationTest {
      
          private ISiteService service;
      
          @Before
          public void init() {
              service = new SiteService();
          }
      
          @Test
          public void whenUsingServiceToReadWordpressFeed_thenCorrect() {
              Site site = new Site("/feed/");
              List articles = service.getArticlesFromSite(site);
      
              assertNotNull(articles);
              for (SiteArticle article : articles) {
                  assertNotNull(article.getTitle());
                  assertNotNull(article.getLink());
              }
          }
      
          @Test
          public void whenUsingRomeToReadBloggerFeed_thenCorrect() {
              Site site = new Site("http://blogname.blogspot.com/feeds/posts/default");
              List articles = service.getArticlesFromSite(site);
      
              assertNotNull(articles);
              for (SiteArticle article : articles) {
                  assertNotNull(article.getTitle());
                  assertNotNull(article.getLink());
              }
          }
      }

      ここには明らかに少し重複がありますが、後で対処できます。

      9. 結論

      今回の記事では、Redditへの投稿のスケジューリングをより簡単にする、新しい小さな機能に注目しました。