天天看点

使用FreeMarker/Jsp(WebWork2)生成静态/动态RSS文件

 使用FreeMarker/Jsp(WebWork2)生成静态/动态RSS文件

scud(飞云小侠)  http://www.jscud.com 转载请注明作者/来源

关键字:rss,freemarker,rss.xml,webwork2

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>[email protected](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函数库的函数如下(日期的函数参考上一篇文章):

    public static String formatRssCData(String content)

    {

        String result = StringFunc.replace(content,"//]//]>","]]&gt;");

        return result;

    }

    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文件的代码如下:

    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>[email protected](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的使用 :)