SiNBLOG

140文字に入らないことを、極稀に書くBlog

slim3で、RSS配信を実装してみた。

作成中のローカルなコミュニティが集まる掲示板に、RSS配信を実装したい!
ということで、やってみた。

とりあえず、RSSについてまったく知らなかったので、とりあえずWikiPediaさんを見た。
RSS - Wikipedia

日本では、RSS1.0とRSS2.0を実装してれば良さそうなので、そうすることに。


次はslim3でどうやってxmlを返すのかという点。
こちらも調べたら先駆者様がいらっしゃった。
Google AppEngine/Java + slim3 でフィード生成したときのメモ - ねじろぐ @drillbits


これで、xmlを返すやり方は分かった!
しかし、RSSの構造をよく知らない上に、規格がたくさんあるため手で作るのは辛い・・・。
何かライブラリは無いのかな?と思い、これまた調べる。

Oracle(Sunが作ったのかな?)が作ったライブラリが良さそうなので、これを採用!
rometools.org - このウェブサイトは販売用です! -&nbsprometools リソースおよび情報

ROMEを動かすためにはJDOMのライブラリも必要ということで、こちらも採用!
JDOM


これでネタは揃ったので、実装してみた!

まずはAppRouterにRSSのFeedTypeをURLに埋め込むように実装。


public AppRouter() {
addRouting("/bbs/feed/{feedType}", "/bbs/feed?feedType={feedType}");
}


Controllerで、FeedTypeを受け取り、responseに書きこむ。


public class FeedController extends AbstractController {

private static final String MIME_TYPE = "application/xml; charset=UTF-8";

/** FeedService */
private FeedService feedService = new FeedService();

/**
* エントリーポイント
*/
@Override
public Navigation run() throws Exception {
String feedType = getFeedType(getRequestParam("feedType"));

SyndFeed feed = feedService.getFeed();
feed.setFeedType(feedType);
response.setContentType(MIME_TYPE);
SyndFeedOutput output = new SyndFeedOutput();
output.output(feed, response.getWriter());

return null;
}

/**
* 引数のFeedTypeから、ROMEのFeedTypeを取得する
*
* @param reqFeedType
* @return
*/
protected String getFeedType(String reqFeedType) {
final String RSS10 = "rss_1.0";
final String RSS20 = "rss_2.0";

if (StringUtil.isEmpty(reqFeedType)) {
return RSS10;
}

final String RSS10_PARAM = "10";
final String RSS20_PARAM = "20";

if (RSS10_PARAM.equals(reqFeedType)) {
return RSS10;
} else if (RSS20_PARAM.equals(reqFeedType)) {
return RSS20;
}

return RSS10;
}
}

SyndFeed#setFeedType(String)で指定してやれば、自動的に該当のRSSを生成してくれる。
今回はRSS1.0とRSS2.0しか対応してないが、Atomも生成できると書いてあった。


掲示板の書き込みから、SyndFeedを作る部分はService側で実装した。
常に最新の状態は必要ないと思い、Memcacheに入れている。
いつもMemcacheを使う時に思うのだが、Keyの値にセオリーとかはあるのだろうか?
何となくで指定しているので、とても不安・・・。


public class FeedService {

private BBSService bbsService = new BBSService();

/**
* BBS RSS Feedを取得
*
* @return
* @throws IOException
* @throws FeedException
*/
public SyndFeed getFeed() {
final String METHOD_NAME = "getFeed";
String memcacheKey = this.getClass().getCanonicalName() + METHOD_NAME;
if (Memcache.contains(memcacheKey)) {
return Memcache.get(memcacheKey);
}
SyndFeed feed = createFeed();
Memcache.put(memcacheKey, feed);
return feed;
}

/**
* BBS RSS Feedを生成
*
* @return
* @throws IOException
* @throws FeedException
*/
protected SyndFeed createFeed() {
SyndFeed feed = new SyndFeedImpl();
feed.setTitle("RSS Title");
feed.setLink("http://hoge.com/bbs/");
feed.setDescription("RSS Description");

List entries = new ArrayList();
List bbsPosts = bbsService.getBBSPostList();

for (BBSPost bbsPost : bbsPosts) {
entries.add(buildeEntry(bbsPost));
}

feed.setEntries(entries);

return feed;
}

/**
* BBSPostからSyndEntryを作成
*
* @param bbsPost
* @return
*/
protected SyndEntry buildeEntry(BBSPost bbsPost) {
SyndEntry entry = new SyndEntryImpl();
String title =
String.format(
"%s(%s)さんの書き込み",
bbsPost.getTwitterScreenName(),
bbsPost.getTwitterName());
entry.setTitle(title);
entry.setLink("http://hoge.com/bbs/"); //個別のページは無いので、掲示板トップ
entry.setPublishedDate(bbsPost.getEntryDate());

SyndContent description = new SyndContentImpl();
description.setType("text/plain");
description.setValue(bbsPost.getContent());

entry.setDescription(description);
return entry;
}
}


後は、htmlのにリンクを貼る。





とりあえず、以上でRSS配信が実装できた!
実際のソースはこちら。
Google Code Archive - Long-term storage for Google Code Project Hosting.
Google Code Archive - Long-term storage for Google Code Project Hosting.
Google Code Archive - Long-term storage for Google Code Project Hosting.
Google Code Archive - Long-term storage for Google Code Project Hosting.


以下は課題点

  1. 掲示板の全書き込みを取得して、RSSを生成しているので、書き込みが増えると負荷が増える。
  2. 掲示板の書き込みを、そのまま突っ込んでいるだけなので、改行とかが反映されていない。

最新の10件だけを抽出して、RSS配信するとかでも良いのだろうか?
Wikipediaをさらっと読んだ程度なので、まだ分からないことがたくさんある。


2011/12/28 追記
gae office hour でさらっと質問してきたので追記。
上記の例だと、リクエスト時にdatastoreから必要なデータを取得してRSS用のXMLを返している。
これとは別の方法で、更新時に、RSS用のXMLを作成し、Blobstore に入れるという手がある。
Blogのように、更新が1日に1回程度の場合、こちらの方が良いかもしれません。
こちらのsampleでも、そのようにしているそうです。
Nick's Blog