slim3で、RSS配信を実装してみた。
作成中のローカルなコミュニティが集まる掲示板に、RSS配信を実装したい!
ということで、やってみた。
とりあえず、RSSについてまったく知らなかったので、とりあえずWikiPediaさんを見た。
RSS - Wikipedia
日本では、RSS1.0とRSS2.0を実装してれば良さそうなので、そうすることに。
次はslim3でどうやってxmlを返すのかという点。
こちらも調べたら先駆者様がいらっしゃった。
Google AppEngine/Java + slim3 でフィード生成したときのメモ - ねじろぐ @drillbits
これで、xmlを返すやり方は分かった!
しかし、RSSの構造をよく知らない上に、規格がたくさんあるため手で作るのは辛い・・・。
何かライブラリは無いのかな?と思い、これまた調べる。
Oracle(Sunが作ったのかな?)が作ったライブラリが良さそうなので、これを採用!
rometools.org - このウェブサイトは販売用です! - rometools リソースおよび情報
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 ();
ListbbsPosts = 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.
以下は課題点
最新の10件だけを抽出して、RSS配信するとかでも良いのだろうか?
Wikipediaをさらっと読んだ程度なので、まだ分からないことがたくさんある。
2011/12/28 追記
gae office hour でさらっと質問してきたので追記。
上記の例だと、リクエスト時にdatastoreから必要なデータを取得してRSS用のXMLを返している。
これとは別の方法で、更新時に、RSS用のXMLを作成し、Blobstore に入れるという手がある。
Blogのように、更新が1日に1回程度の場合、こちらの方が良いかもしれません。
こちらのsampleでも、そのようにしているそうです。
Nick's Blog