RSS在网络上大行其道,各种网站都加上RSS支持,我最近也研究了一下,给我的文章也加上了RSS订阅.
RSS目前用的也有几个版本,很是混乱,下面以RSS2.0为例来说明.
网络上有个rsslibj库,是用来生成rss支持文件的,不过已经好久没有更新了,它是用xml的方式生成的.本文的例子不用到任何xml解析器,不过当然要知道最后生成的XML文件的格式才行,关于RSS规范,可以浏览一下 http://blogs.law.harvard.edu/tech/rss .
在计划生成RSS文件的时候,顺便搜索了一下JIRA和Confluence的程序,发现它们分别是用模板方式和JSP动态页面来展示的.于是我也想到两种方式:
1.用FreeMarker生成静态文件,适用于更新不是很频繁的内容.
2.用JSP动态展示,适合更新频率高,种类繁多的内容.
还是以本站的新闻举例,其中的新闻信息类参考 http://www.jscud.com/srun/news/viewhtml/3_2005_8/76.htm ,此处不在列出.
(一) 先说FreeMarker方式.
根据RSS的规范,得到模板如下:
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>JScud Develop</title>
<link>http://www.jscud.com/</link>
<language>zh-cn</language>
<description >JScud Develop By Scud</description>
<webMaster>xxx@21cn.com(scud)</webMaster>
<lastBuildDate>${rssutil.formatRssDate(now)}</lastBuildDate>
<#list newslist as onenews>
<item>
<title>${onenews.title?xml}</title>
<link>http://www.jscud.com/srun/news/viewhtml/${onenews.htmlFilePath}/${onenews.nid}.htm</link>
<pubDate>${rssutil.formatRssDate(onenews.addtime)}</pubDate>
<description><![CDATA[
${rssutil.formatRssCData(onenews.showContent)}
]]>
</description>
</item>
</#list>
</channel>
</rss>
其中的网址和网站名称可以根据自己的实际情况修改.
我每次取出最新的20条文章来生成RSS,不过内容比较多,生成的RSS文件比较大,看到有的网站的description只是放了文章摘要的内容,这样文件就小多了.总之是根据自己的需求设计吧.
其中用到的RssUtil函数库的函数如下(日期的函数参考上一篇文章):
/**
* 把]]>替换为]]>
* @param content 内容
* @return 格式化后的内容
*/
public static String formatRssCData(String content)
{
String result = StringFunc.replace(content,"\\]\\]>","]]>");
return result;
}
/**
* 格式化为xml需要的字符串
* @param field 内容
* @return 格式化后的串
*/
public static String formatString2XML(String field)
{
return StringFunc.str2TextXML(field);
}
public static String getNowDateTime()
{
return formatRssDate(DateTime.getNowTimestamp());
}
利用FreeMarker生成静态文件的代码如下:
private Configuration freemarker_cfg = null;
protected Configuration getFreeMarkerCFG()
{
if (null == freemarker_cfg)
{
// Initialize the FreeMarker configuration;
// - Create a configuration instance
freemarker_cfg = new Configuration();
freemarker_cfg.setClassForTemplateLoading(this.getClass(), "/htmlskin");
freemarker_cfg.setDefaultEncoding("GBK");
}
return freemarker_cfg;
}
public boolean geneFileByFreeMarker(String templateFileName, Map propMap, String filePath,
String fileName, String encode)
{
try
{
Template t = getFreeMarkerCFG().getTemplate(templateFileName);
File afile = new File(filePath + "/" + fileName);
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(afile),
encode));
propMap.put("baseurl", PropSet.getStringProp("url.root"));
t.process(propMap, out);
}
catch (TemplateException e)
{
LogMan.error("Error while processing FreeMarker template " + templateFileName, e);
return false;
}
catch (IOException e)
{
LogMan.error("Error while generate File " + fileName, e);
return false;
}
return true;
}
新闻系统中调用重新生成RSS文件的代码如下:
/**
* 重新生成RSS文件.
*
* @param nid 更新的新闻的id,如果不包含在最新的新闻里,则不更新RSS.nid <1则更新
*
* @return 是否成功
*/
private boolean renewRSS(int nid)
{
List newsList = 装载新闻的代码
boolean shouldUpdate = false;
if (nid > 0)
{
for (int i = 0; i < newsList.size(); i++)
{
NewsItem aNews = (NewsItem) newsList.get(i);
if (aNews.getNid() == nid)
{
shouldUpdate = true;
break;
}
}
}
else
{
shouldUpdate = true;
}
//不更新,则返回
if (!shouldUpdate)
{
return true;
}
Map root = new HashMap();
root.put("rssutil",new RSSUtil());
root.put("newslist", newsList);
root.put("now",DateTime.getNowTimestamp());
geneFileByFreeMarker("/news/rss.ftl", root, PropSet.getStringProp("rss.rssdir"), PropSet
.getStringProp("rss.rssfile"), "UTF-8");
return true;
}
在增加或者更新/删除新闻的地方需要调用这个renewRSS函数.
(二)JSP动态方式
相对静态方式而言,简单的多,不过效率上可能就不太好了.
webwork2的Action代码如下:
newsList = 装载新闻代码
return SUCCESS;
视图Jsp如下:
<%@ page contentType="text/xml; charset=UTF-8"%>
<%@ taglib uri="jscud" prefix="jscud" %>
<%@ taglib uri="webwork" prefix="ww" %>
<ww:bean name="’com.jscud.www.util.RSSUtil’" id="rssUtil" />
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>JScud Develop</title>
<link>http://www.jscud.com/</link>
<language>zh-cn</language>
<description >JScud Develop By Scud</description>
<webMaster>xxx@21cn.com(scud)</webMaster>
<lastBuildDate><ww:property value="#rssUtil.nowDateTime" /></lastBuildDate>
<ww:iterator value="newsList">
<item>
<title><ww:property value="#rssUtil.formatString2XML(title)"/></title>
<link>http://www.jscud.com/srun/news/viewhtml/<ww:property value="htmlFilePath" />/<ww:property value="nid" />.htm</link>
<pubDate><ww:property value="#rssUtil.formatRssDate(addtime)" /></pubDate>
<description><![CDATA[
<ww:property value="#rssUtil.formatRssCData(showContent)"/>
]]>
</description>
</item>
</ww:iterator>
</channel>
</rss>
jsp的方式简单多了,上面的jsp里面还演示了ww:bean的使用 :)
上面的类里面引用了很多其他的工具类,这里不一一列出,可以自己实现它们,都是很简单的类. :)
RSS目前用的也有几个版本,很是混乱,下面以RSS2.0为例来说明.
网络上有个rsslibj库,是用来生成rss支持文件的,不过已经好久没有更新了,它是用xml的方式生成的.本文的例子不用到任何xml解析器,不过当然要知道最后生成的XML文件的格式才行,关于RSS规范,可以浏览一下 http://blogs.law.harvard.edu/tech/rss .
在计划生成RSS文件的时候,顺便搜索了一下JIRA和Confluence的程序,发现它们分别是用模板方式和JSP动态页面来展示的.于是我也想到两种方式:
1.用FreeMarker生成静态文件,适用于更新不是很频繁的内容.
2.用JSP动态展示,适合更新频率高,种类繁多的内容.
还是以本站的新闻举例,其中的新闻信息类参考 http://www.jscud.com/srun/news/viewhtml/3_2005_8/76.htm ,此处不在列出.
(一) 先说FreeMarker方式.
根据RSS的规范,得到模板如下:
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>JScud Develop</title>
<link>http://www.jscud.com/</link>
<language>zh-cn</language>
<description >JScud Develop By Scud</description>
<webMaster>xxx@21cn.com(scud)</webMaster>
<lastBuildDate>${rssutil.formatRssDate(now)}</lastBuildDate>
<#list newslist as onenews>
<item>
<title>${onenews.title?xml}</title>
<link>http://www.jscud.com/srun/news/viewhtml/${onenews.htmlFilePath}/${onenews.nid}.htm</link>
<pubDate>${rssutil.formatRssDate(onenews.addtime)}</pubDate>
<description><![CDATA[
${rssutil.formatRssCData(onenews.showContent)}
]]>
</description>
</item>
</#list>
</channel>
</rss>
其中的网址和网站名称可以根据自己的实际情况修改.
我每次取出最新的20条文章来生成RSS,不过内容比较多,生成的RSS文件比较大,看到有的网站的description只是放了文章摘要的内容,这样文件就小多了.总之是根据自己的需求设计吧.
其中用到的RssUtil函数库的函数如下(日期的函数参考上一篇文章):
/**
* 把]]>替换为]]>
* @param content 内容
* @return 格式化后的内容
*/
public static String formatRssCData(String content)
{
String result = StringFunc.replace(content,"\\]\\]>","]]>");
return result;
}
/**
* 格式化为xml需要的字符串
* @param field 内容
* @return 格式化后的串
*/
public static String formatString2XML(String field)
{
return StringFunc.str2TextXML(field);
}
public static String getNowDateTime()
{
return formatRssDate(DateTime.getNowTimestamp());
}
利用FreeMarker生成静态文件的代码如下:
private Configuration freemarker_cfg = null;
protected Configuration getFreeMarkerCFG()
{
if (null == freemarker_cfg)
{
// Initialize the FreeMarker configuration;
// - Create a configuration instance
freemarker_cfg = new Configuration();
freemarker_cfg.setClassForTemplateLoading(this.getClass(), "/htmlskin");
freemarker_cfg.setDefaultEncoding("GBK");
}
return freemarker_cfg;
}
public boolean geneFileByFreeMarker(String templateFileName, Map propMap, String filePath,
String fileName, String encode)
{
try
{
Template t = getFreeMarkerCFG().getTemplate(templateFileName);
File afile = new File(filePath + "/" + fileName);
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(afile),
encode));
propMap.put("baseurl", PropSet.getStringProp("url.root"));
t.process(propMap, out);
}
catch (TemplateException e)
{
LogMan.error("Error while processing FreeMarker template " + templateFileName, e);
return false;
}
catch (IOException e)
{
LogMan.error("Error while generate File " + fileName, e);
return false;
}
return true;
}
新闻系统中调用重新生成RSS文件的代码如下:
/**
* 重新生成RSS文件.
*
* @param nid 更新的新闻的id,如果不包含在最新的新闻里,则不更新RSS.nid <1则更新
*
* @return 是否成功
*/
private boolean renewRSS(int nid)
{
List newsList = 装载新闻的代码
boolean shouldUpdate = false;
if (nid > 0)
{
for (int i = 0; i < newsList.size(); i++)
{
NewsItem aNews = (NewsItem) newsList.get(i);
if (aNews.getNid() == nid)
{
shouldUpdate = true;
break;
}
}
}
else
{
shouldUpdate = true;
}
//不更新,则返回
if (!shouldUpdate)
{
return true;
}
Map root = new HashMap();
root.put("rssutil",new RSSUtil());
root.put("newslist", newsList);
root.put("now",DateTime.getNowTimestamp());
geneFileByFreeMarker("/news/rss.ftl", root, PropSet.getStringProp("rss.rssdir"), PropSet
.getStringProp("rss.rssfile"), "UTF-8");
return true;
}
在增加或者更新/删除新闻的地方需要调用这个renewRSS函数.
(二)JSP动态方式
相对静态方式而言,简单的多,不过效率上可能就不太好了.
webwork2的Action代码如下:
newsList = 装载新闻代码
return SUCCESS;
视图Jsp如下:
<%@ page contentType="text/xml; charset=UTF-8"%>
<%@ taglib uri="jscud" prefix="jscud" %>
<%@ taglib uri="webwork" prefix="ww" %>
<ww:bean name="’com.jscud.www.util.RSSUtil’" id="rssUtil" />
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>JScud Develop</title>
<link>http://www.jscud.com/</link>
<language>zh-cn</language>
<description >JScud Develop By Scud</description>
<webMaster>xxx@21cn.com(scud)</webMaster>
<lastBuildDate><ww:property value="#rssUtil.nowDateTime" /></lastBuildDate>
<ww:iterator value="newsList">
<item>
<title><ww:property value="#rssUtil.formatString2XML(title)"/></title>
<link>http://www.jscud.com/srun/news/viewhtml/<ww:property value="htmlFilePath" />/<ww:property value="nid" />.htm</link>
<pubDate><ww:property value="#rssUtil.formatRssDate(addtime)" /></pubDate>
<description><![CDATA[
<ww:property value="#rssUtil.formatRssCData(showContent)"/>
]]>
</description>
</item>
</ww:iterator>
</channel>
</rss>
jsp的方式简单多了,上面的jsp里面还演示了ww:bean的使用 :)
上面的类里面引用了很多其他的工具类,这里不一一列出,可以自己实现它们,都是很简单的类. :)