完成"issue 12"的学习日记rrs支持

  作了一点完善。rss的全部代码已经提交完毕,并且用在了现在的系统中。

  但是,我发现,至今为止,基本没有什么人用rss来订阅学习日记的的内容。我也不知道为什么?可能最主要的原因是学习日记的内容太少了,太浅了,订阅的价值不大;其次是rss订阅还不为一些朋友了解和习惯使用吧。

为什么学习日记没有实现rss0.91的支持

  在使用rome生成的程序中,我发现了rss0.91的一些限制:例如:language是channel的必需元素,copyRight的长度不能超过100个字符(?),description的长度不能超过?个字符

  我生成的内容不符合这些限制,所以就不支持rss0.91了(包括RSS 0.91 Netscape 和 RSS 0.91 Userland)。

  我只是从程序的出错信息中得知这些限制的,还没有具体去学习这些规范。

学习日记新增RSS订阅功能简介(NEW);什么是RSS?(转帖)

                     学习日记新增RSS订阅功能简介(NEW)

××××××××××××××××××××××××××××××××××××××××××××××××××××××××

(详见:http://www.learndiary.com/dispatchPageAction.do?act=rss)

学习日记网站 RSS 订阅使用说明:

本站RSS订阅使用rome动态生成,除了下面链接中的默认订阅,您可以修改url中参数取得您定制的RSS订阅(包括定制:RSS版本,条目数,用户等),(注意:参数大小写敏感):

参数"type": 为您订阅的类型,即为下面7种和"所有目标 "页面的2种;

参数"feedType": 为订阅的rss类型,包括:RSS 0.90, RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0, RSS 2.0, Atom 0.3, Atom 1.0 ,参数为: RSS类型 + "_" + RSS版本号, 如:atom_0.3(必须全部小写,RSS 0.91学习日记未实现支持);

参数"entriesNum": 为您RSS订阅的条目数,默认为39条;

参数"userName": 为您的用户名;

参数"channelID": 为您在"所有目标 "页面订阅某个目标下面的条目的目标ID号。

========================================================

  根据我的理解,RSS就是在一个RSS阅读器里订阅所有你感兴趣的、利用了RSS发布的网上的信息,这样,在你打开RSS阅读器或者RSS阅读器在系统中运行固定的时间间隔(例如1个小时)后,RSS阅读器自动连接到这些提供了RSS发布的网站上并自动更新相关的信息。

  这样,你就可以用一个RSS阅读器获得你感兴趣的所有最新信息,而不用登录到它们的一个个的网站上去浏览。

  我现在在用的一款RSS阅读器是新浪网发布的,你也可以一试:http://rss.sina.com.cn。大家如果有其它的好的RSS阅读器也希望在这里跟帖说一下。

  下面是一篇来自网上的转帖,供还没有使用过RSS阅读器朋友参考。

                        什么是RSS?(转帖)

××××××××××××××××××××××××××××××××××××××××××××××××××××××××

(转自:http://wm23.com/resource/R01/Internet_1005.htm)

什么是RSS?RSS及其发展历程

(网络营销教学网站 www.wm23.com 2005-01-03)

  RSS是2004年最热门的互联网词汇之一,不过,相对于博客(BLOG)来说,RSS的知名度相应会低很多,而且至今还没有一个非常贴切的中文词汇,也许以后无需中文名,大家都习惯于直接叫RSS了。RSS之所以同BLOG一样会被认为是热门词汇的一个原因,个人推测,应该是许多分析人士认识到RSS将要对互联网内容的浏览方法所产生的巨大影响。

  什么是RSS呢?RSS(Really Simple Syndication)是一种描述和同步网站内容的格式,是目前使用最广泛的XML应用。RSS搭建了信息迅速传播的一个技术平台,使得每个人都成为潜在的信息提供者。发布一个RSS文件后,这个RSS Feed中包含的信息就能直接被其他站点调用,而且由于这些数据都是标准的XML格式,所以也能在其他的终端和服务中使用。

  如果从RSS阅读者的角度来看,完全不必考虑它到底是什么意思,只要简单地理解为一种方便的信息获取工具就可以了。RSS获取信息的模式与加入邮件列表(如电子杂志和新闻邮件)获取信息有一定的相似之处,也就是可以不必登录各个提供信息的网站而通过客户端浏览方式(称为“RSS阅读器”)或者在线RSS阅读方式这些内容。例如,通过一个RSS阅读器,可以同时浏览新浪新闻,也可以浏览搜狐或者百度的新闻(如果你采用了RSS订阅的话)。

  在许多新闻信息服务类网站,会看到这样的按钮   ,有的网站使用一个图标,有的同时使用两个,这就是典型的提供RSS订阅的标志,这个图标一般链接到订阅RSS信息源的URL。当然,即使不用这样的图标也是可以的,只要提供订阅RSS信息源的URL即可,如网上营销新观察提供的RSS订阅URL是:http://www.marketingman.net/rss.xml

  使用RSS获取信息的前提是,先安装一个RSS阅读器,然后将提供RSS服务的网站加入到RSS阅读器的频道即可。大部分RSS阅读器本身也预设了部分RSS频道,如新浪新闻、百度新闻等。

  RSS基础知识:如何利用RSS阅读器订阅RSS新闻内容?如何免费下载RSS阅读器?(http://www.marketingman.net/wmtheo/zh272.htm)

  常用的RSS阅读器:周博通RSS阅读器(http://www.potu.com/) 看天下网络资讯浏览器(http://www.kantianxia.com/)

  网上营销新观察专题文章:RSS营销研究(http://www.marketingman.net/topics/020_RSS-marketing.htm)

  【RSS实用知识】:关于RSS订阅与RSS阅读的常见问题解答(网上营销新观察 冯英健) (http://www.marketingman.net/wmtheo/zh272.htm)

  为了进一步了解RSS及其发展历程的有关背景知识,下面摘录了2003年10月平文胜为时代营销撰写的有关RSS技术层面的介绍文章。仅供参考。网上此类介绍文章也不少,有兴趣的请到网上检索更多信息。例如维基百科对于RSS的定义、RSS规范、RSS专用阅读器和RSS在线阅读器、中文RSS搜索引擎等等(http://zh.wikipedia.org/wiki/RSS)

  RSS及其发展历程简介 (时代营销 平文胜 2003-10-10)

  RSS是一种描述和同步网站内容的格式,是目前使用最广泛的XML应用。RSS应用在国外已经非常普遍,从个人博客(Blog)栏目、企业站点到世界级的门户都提供基于RSS的服务,如IBM公司站点的中文新闻RSS http://www.ibm.com/news/cn/zh/index.rss ,YAHOO站点的http://news.yahoo.com/rss ,微软MSDN站点的http://msdn.microsoft.com/aboutmsdn/rss.asp 等等。

  1、 RSS的历史

  那么RSS究竟代表什么呢?比较普遍的有两种说法,一种是“Rich Site Summary”或“RDF Site Summary”,另一种是“Really Simple Syndication”,之所以有这些分歧,需要从RSS发展的历史说起。

  最初的0.90版本RSS是由Netscape公司设计的,目的是用来建立一个整合了各主要新闻站点内容的门户,但是0.90版本的RSS规范过于复杂,而一个简化的RSS 0.91版本也随着Netscape公司对该项目的放弃而于2000年暂停。

  不久,一家专门从事博客写作软件开发的公司UserLand接手了RSS 0.91版本的发展,并把它作为其博客写作软件的基础功能之一继续开发,逐步推出了0.92、0.93和0.94版本。随着网络博客的流行,RSS作为一种基本的功能也被越来越多的网站和博客软件支持。

  在UserLand公司接手并不断开发RSS的同时,很多的专业人士认识到需要通过一个第三方、非商业的组织,把RSS发展成为一个通用的规范,并进一步标准化。于是2001年一个联合小组在0.90版本RSS的开发原则下,以W3C新一代的语义网技术RDF(Resource Description Framework)为基础,对RSS进行了重新定义,发布RSS1.0,并将RSS定义为“RDF Site Summary”。但是这项工作没有与UserLand公司进行有效的沟通,UserLand公司也不承认RSS 1.0的有效性,并坚持按照自己的设想进一步开发出RSS的后续版本,到2002年9月发布了最新版本RSS 2.0,UserLand公司将RSS定义为“Really Simple Syndication”。

  目前RSS已经分化为RSS 0.9x/2.0和RSS 1.0两个阵营,由于分歧的存在和RSS 0.9x/2.0的广泛应用现状,RSS 1.0还没有成为标准化组织的真正标准。

  2、 RSS目前的版本和推荐

  到目前为止,RSS共有七种版本,推荐使用的是RSS 1.0和RSS 2.0,对于一些基本的站点同步,也可以选用RSS 0.91。

  3、 RSS的语法介绍

  一个RSS文件就是一段规范的XML数据,该文件一般以rss,xml或者rdf作为后缀。下面我们选择http://msdn.microsoft.com/visualc/rss.xml中的一部分作为例子简单说(略)

  4、 RSS的联合(Syndication)和聚合(Aggregation)

  发布一个RSS文件(一般称为RSS Feed)后,这个RSS Feed中包含的信息就能直接被其他站点调用,而且由于这些数据都是标准的XML格式,所以也能在其他的终端和服务中使用,如PDA、手机、邮件列表等。而且一个网站联盟(比如专门讨论旅游的网站系列)也能通过互相调用彼此的RSS Feed,自动的显示网站联盟中其他站点上的最新信息,这就叫着RSS的联合。这种联合就导致一个站点的内容更新越及时、RSS Feed被调用的越多,该站点的知名度就会越高,从而形成一种良性循环。

  而所谓RSS聚合,就是通过软件工具的方法从网络上搜集各种RSS Feed并在一个界面中提供给读者进行阅读。这些软件可以是在线的WEB工具,如http://my.netscape.com ,http://my.userland.com , http://www.xmltree.com ,http://www.moreover.com ,http://www.oreillynet.com/meerkat 等,也可以是下载到客户端安装的工具

  5、 RSS的未来发展

  随着越来越多的站点对RSS的支持,RSS已经成为目前最成功的XML应用。RSS搭建了信息迅速传播的一个技术平台,使得每个人都成为潜在的信息提供者。相信很快我们就会看到大量基于RSS的专业门户、聚合站点和更精确的搜索引擎。

参考文献:

1、 RSS 0.9 Specification http://www.purplepages.ie/RSS/netscape/rss0.90.html

2、 RSS 1.0 Specification http://web.resource.org/rss/1.0/spec

3、 RSS 2.0 Specification http://blogs.law.harvard.edu/tech/rss

rss支持第一次代码提交

  程序类基本完成,页面还没有做。使用rome可以较好的实现所有rss版本和atom的feed。个人认为还是应用得比较成功的。今天早上已经把全部代码和argoUML0.18.1的粗略设计提交到了cvs库。

  主要类的实现概略:(希望得到你的意见或建议,也供想使用rome的朋友参考。)

  1、

//$ Id: RSSAction.java,v 1.0 2006/02/26 20:49:06 dashing_meng Exp $

//Copyright (c) 2004-2005 Http://www.learndiary.com. All Rights Reserved.

//Permission to use, copy, modify, and distribute this software and its

//documentation without fee, and without a written agreement is hereby

//granted, provided that the above copyright notice and this paragraph

//appear in all copies.  This software program and documentation are

//copyrighted by http://www.learndiary.com. The software program and

//documentation are supplied "AS IS", without any accompanying services

//from The LearnDiary. The LearnDiary does not warrant that the operation

//of the program will be uninterrupted or error-free. The end-user

//understands that the program was developed for research purposes and is

//advised not to rely exclusively on the program for any reason.

//IN NO EVENT SHALL HTTP://WWW.LEARNDIARY.COM BE LIABLE TO ANY PARTY FOR

//DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,

//INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS

//DOCUMENTATION, EVEN IF HTTP://WWW.LEARNDIARY.COM HAS BEEN ADVISED OF THE

//POSSIBILITY OF SUCH DAMAGE. HTTP://WWW.LEARNDIARY.COM SPECIFICALLY

//DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE

//SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND

//HTTP://WWW.LEARNDIARY.COM HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,

//SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

package com.learndiary.website.action.rss;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts.action.ActionForward;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.apache.struts.action.ActionMapping;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;

import org.apache.struts.action.ActionForm;

import com.learndiary.website.util.rss.*;

import com.sun.syndication.io.FeedException;

/**

 * action for generating rss feed.

 * @author http://www.learndiary.com,LearnDiary Develop Group

 */

public class RSSAction extends Action {

  /* {src_lang=Java}*/

  private Log __log = LogFactory.getFactory().getInstance(this.getClass());

  ;

  /* {transient=false, volatile=false}*/

  /**

   *  pseudo code:

   *  {

   *    //the rss feed type,includes:

   *    //latestDiariesOfMyProcessGoal, latestAdvicesOfMyDiaries,

   *    //latestGoals, mostJoinedGoals, latestDiaries, latestAdvices,

   *    //latestDiariesOfGoal, latestAdvicesOfGoal,etc..

   *    String type=request.getParameter("type");

   *   

   *    //feed type,includes:

   *    //RSS 0.90, RSS 0.91 Netscape, RSS 0.91 Userland,

   *    //RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0,

   *    // RSS 2.0, Atom 0.3, Atom 1.0

   *    String rssVersion = request.getParameter("feedType");

   * 

   *    //entries number:

   *    //user can specify how many entries he would like to see,

   *    //the default entries number is 39.

   *    int entriesNum=Integer.parseInt(request.getParemeter("entriesNum"));

   * 

   *    //user's name:

   *    //for getting specified user's entries.

   *    String userName=request.getParameter("userName");

   * 

   *    //channel article's ID:

   *    //it is only for subscribing a goal's sub-entries,goalID.

   *    int  channelID=Integer.parseInt(request.getParemeter("channelID"));

   *   

   *    if (type.equal("latestDiaries")){

   *      RSSGenerator generator = new  LatestDiariesRSS(feedType, entriesNum);

   *      generator.outputFeed();

   *    }else if(type.equal("latestAdvices")){

   *      RSSGenerator generator = new  LatestAdvicesRSS(feedType, entriesNum);

   *      generator.outputFeed();

   *    }else if(type.equal("latestDiariesOfMyProcessGoal")){

   *      RSSGenerator generator = new  LatestDiariesOfMyProcessGoalRSS(feedType, entriesNum, userName);

   *      generator.outputFeed();

   *    }else if(type.equal("latestMyDiariesOfMyProcessGoal")){

   *      RSSGenerator generator = new  LatestMyDiariesOfMyProcessGoalRSS(feedType, entriesNum, userName);

   *      generator.outputFeed();

   *    }else if(type.equal("latestAdvicesOfMyDiaries")){

   *      RSSGenerator generator = new  LatestAdvicesOfMyDiariesRSS(feedType, entriesNum, userName);

   *      generator.outputFeed();

   *    }else if(type.equal("latestDiariesOfGoal")){

   *      RSSGenerator generator = new  LatestDiariesOfGoalRSS(feedType, entriesNum, channelID);

   *      generator.outputFeed();

   *    }else if(type.equal("latestAdvicesOfGoal")){

   *      RSSGenerator generator = new  LatestAdvicesOfGoalRSS(feedType, entriesNum, channelID);

   *      generator.outputFeed();

   *    }else if(type.equal("latestGoals")){

   *      RSSGenerator generator = new  LatestGoalsRSS(feedType, entriesNum);

   *      generator.outputFeed();

   *    }else if(type.equal("mostJoinedGoals")){

   *      RSSGenerator generator = new  MostJoinedGoalsRSS(feedType, entriesNum);

   *      generator.outputFeed();

   *    }else {

   *      show "error type" message;

   *    }

   *  }//end of excute() method

   *  

   */

  public ActionForward execute(

    ActionMapping mapping,

    ActionForm form,

    HttpServletRequest request,

    HttpServletResponse response) {

    //the rss feed type,includes:

    //latestDiariesOfMyProcessGoal, latestAdvicesOfMyDiaries,

    //latestGoals, mostJoinedGoals, latestDiaries, latestAdvices,

    //latestDiariesOfGoal, latestAdvicesOfGoal,etc..

    String type = request.getParameter("type");

    //feed type,includes:

    //RSS 0.90, RSS 0.91 Netscape, RSS 0.91 Userland,

    //RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0,

    // RSS 2.0, Atom 0.3, Atom 1.0

    String feedType = request.getParameter("feedType");

    //entries number:

    //user can specify how many entries he would like to see,

    //the default entries number is 39.

    int entriesNum = Integer.parseInt(request.getParameter("entriesNum"));

    //user's name:

    //for getting specified user's entries.

    String userName = request.getParameter("userName");

    //channel article's ID:

    //it is only for subscribing a goal's sub-entries,goalID.

    int channelID = 0;

    String channelIDStr = request.getParameter("channelID");

    if (channelIDStr != null && !channelIDStr.equals(""))

      channelID = Integer.parseInt(channelIDStr);

    try {

      if (type.equals("latestDiaries")) {

        RSSGenerator generator = new LatestDiariesRSS(feedType, entriesNum);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestDiaries:feedType="

            + feedType

            + " entriesNum="

            + entriesNum);

      } else if (type.equals("latestAdvices")) {

        RSSGenerator generator = new LatestAdvicesRSS(feedType, entriesNum);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestAdvices:feedType="

            + feedType

            + " entriesNum="

            + entriesNum);

      } else if (type.equals("latestDiariesOfMyProcessGoal")) {

        RSSGenerator generator =

          new LatestDiariesOfMyProcessGoalRSS(feedType, entriesNum, userName);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestDiariesOfMyProcessGoal:feedType="

            + feedType

            + " entriesNum="

            + entriesNum

            + " userName="

            + userName);

      } else if (type.equals("latestMyDiariesOfMyProcessGoal")) {

        RSSGenerator generator =

          new LatestMyDiariesOfMyProcessGoalRSS(feedType, entriesNum, userName);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestMyDiariesOfMyProcessGoal:feedType="

            + feedType

            + " entriesNum="

            + entriesNum

            + " userName="

            + userName);

      } else if (type.equals("latestAdvicesOfMyDiaries")) {

        RSSGenerator generator =

          new LatestAdvicesOfMyDiariesRSS(feedType, entriesNum, userName);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestAdvicesOfMyDiaries:feedType="

            + feedType

            + " entriesNum="

            + entriesNum

            + " userName="

            + userName);

      } else if (type.equals("latestDiariesOfGoal")) {

        RSSGenerator generator =

          new LatestDiariesOfGoalRSS(feedType, entriesNum, channelID);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestDiariesOfGoal:feedType="

            + feedType

            + " entriesNum="

            + entriesNum

            + " channelID="

            + channelID);

      } else if (type.equals("latestAdvicesOfGoal")) {

        RSSGenerator generator =

          new LatestAdvicesOfGoalRSS(feedType, entriesNum, channelID);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestAdvicesOfGoal:feedType="

            + feedType

            + " entriesNum="

            + entriesNum

            + " channelID="

            + channelID);

      } else if (type.equals("latestGoals")) {

        RSSGenerator generator = new LatestGoalsRSS(feedType, entriesNum);

        generator.outputFeed(response);

        __log.info(

          "get feed of LatestGoalsRSS:feedType="

            + feedType

            + " entriesNum="

            + entriesNum);

      } else if (type.equals("mostJoinedGoals")) {

        RSSGenerator generator = new MostJoinedGoalsRSS(feedType, entriesNum);

        generator.outputFeed(response);

        __log.info(

          "get feed of mostJoinedGoals:feedType="

            + feedType

            + " entriesNum="

            + entriesNum);

      } else {

        return mapping.findForward("commonFailure");

      }

    } catch (IOException e1) {

      e1.printStackTrace();

    } catch (FeedException e2) {

      e2.printStackTrace();

    } catch (Exception e3) {

      e3.printStackTrace();

    }

    return null;

  }

}

  2、

//$ Id: RSSGenerator.java,v1.4  2006/02/26 20:49:06 dashing_meng Exp $

//Copyright (c) 2004-2005 Http://www.learndiary.com. All Rights Reserved.

//Permission to use, copy, modify, and distribute this software and its

//documentation without fee, and without a written agreement is hereby

//granted, provided that the above copyright notice and this paragraph

//appear in all copies.  This software program and documentation are

//copyrighted by http://www.learndiary.com. The software program and

//documentation are supplied "AS IS", without any accompanying services

//from The LearnDiary. The LearnDiary does not warrant that the operation

//of the program will be uninterrupted or error-free. The end-user

//understands that the program was developed for research purposes and is

//advised not to rely exclusively on the program for any reason.

//IN NO EVENT SHALL HTTP://WWW.LEARNDIARY.COM BE LIABLE TO ANY PARTY FOR

//DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,

//INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS

//DOCUMENTATION, EVEN IF HTTP://WWW.LEARNDIARY.COM HAS BEEN ADVISED OF THE

//POSSIBILITY OF SUCH DAMAGE. HTTP://WWW.LEARNDIARY.COM SPECIFICALLY

//DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE

//SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND

//HTTP://WWW.LEARNDIARY.COM HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,

//SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

package com.learndiary.website.util.rss;

import com.sun.syndication.feed.synd.SyndCategory;

import com.sun.syndication.feed.synd.SyndCategoryImpl;

import com.sun.syndication.feed.synd.SyndContent;

import com.sun.syndication.feed.synd.SyndContentImpl;

import com.sun.syndication.feed.synd.SyndEntry;

import com.sun.syndication.feed.synd.SyndEntryImpl;

import com.sun.syndication.feed.synd.SyndFeed;

import com.sun.syndication.io.FeedException;

import com.sun.syndication.io.SyndFeedOutput;

import com.learndiary.website.Constants;

import com.learndiary.website.Consts;

import com.learndiary.website.model.ArticleInfo;

import java.io.IOException;

import java.io.PrintWriter;

import java.text.DateFormat;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import org.apache.commons.logging.Log;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

import com.learndiary.website.db.ArticleDB;

import com.learndiary.website.dao.TransContext;

import javax.servlet.http.HttpServletResponse;

/**

 * the base abstract class for generating rss feed.

 * @author http://www.learndiary.com,LearnDiary Develop Group

 */

public abstract class RSSGenerator {

  protected static final DateFormat DATE_PARSER =

    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

  /* {transient=false, volatile=false}*/

  protected Log __log = null; //should it be added "static" modifier?

  /* {transient=false, volatile=false}*/

  protected static TransContext trans = null;

  /* {transient=false, volatile=false}*/

  protected static ArticleDB myDB = null;

  /* {transient=false, volatile=false}*/

  protected String feedType = "rss_2.0";

  /* {transient=false, volatile=false}*/

  protected int entriesNum = 39;

  /* {transient=false, volatile=false}*/

  protected final List entries = new ArrayList();

  /* {transient=false, volatile=false}*/

  protected SyndFeed feed = null;

  /* {transient=false, volatile=false}*/

  protected String catName = null;

  /* {transient=false, volatile=false}*/

  /**

   *  output the rss feed xml page

   *  pseudo code:

   *  {

   *    res.setContentType("application/xml; charset=UTF-8");

   *    SyndFeedOutput output = new SyndFeedOutput();

   *    output.output(feed,res.getWriter());

   *  }

   * @param res the HttpServletResponse come from the excute() method of struts Action 

   */

  public void outputFeed(HttpServletResponse res)

    throws IOException, FeedException, Exception {

    try {

      this.setFeed();

    } catch (Exception e1) {

      e1.printStackTrace();

    }

    res.setContentType("application/xml; charset=UTF-8");

    SyndFeedOutput output = new SyndFeedOutput();

    PrintWriter out = res.getWriter();

    try {

      output.output(feed, out);

    } catch (IOException e) {

      e.printStackTrace();

    } catch (FeedException e) {

      e.printStackTrace();

    }

  }

  /**

   *  set rss feed

   */

  abstract protected void setFeed() throws Exception;

  /**

   *  set articles into the entries list of the rss feed

   *  {

   *    List artList=(ArrayList)myDB.getCPageList(0, entriesNum, "article", condition, Consts.ART_WRITE, Consts.DIR_DESC, Consts.HTML_FLAG);

   *    Iterator it=artList.listIterator();

   *     while (it.hasNext()) {

   *        ArticleInfo anArt = (ArticleInfo)it.next();

   *        entries.addEntry(anArt);

   *    }

   *  }

   * @param condition "WHERE" clause in the sql statement,for example:"WHERE parentID=1 AND typeID=2" 

   */

  protected void setEntries(String condition,int orderType,int direction,int htmlFlag) throws Exception {

    List artList = new ArrayList();

    __log.debug("setEntries() in RSSGenerator:entriesNum="+entriesNum+" condition is:"+condition);

    try {

      artList =

        (ArrayList) myDB.getCPageList(

          0,

          entriesNum,

          "article",

          condition,

          orderType,

          direction,

          htmlFlag);

    } catch (Exception e) {

      e.printStackTrace();

    }

    __log.debug("artList is:"+artList);

    if (artList == null)

      return;

    Iterator it = artList.listIterator();

    while (it.hasNext()) {

      ArticleInfo anArt = (ArticleInfo) it.next();

      this.addEntry(anArt);

    }

  }

  /**

   *  add an articleInfo into rss entries list

   *  pseudo code:

   *  {

   *    SyndEntry entry = new SyndEntryImpl();

   *    entry.setAuthor(anArt.getUserName());

   *    entry.setTitle(title);

   *    entry.setLink(link);

   *    entry.setPublishedDate(DATE_PARSER.parse(date));

   *    SyndContent description = new SyndContentImpl();

   *    description.setType("text/plain");

   *    description.setValue(blogContent);

   *    entry.setDescription(description);

   *    List categories = new ArrayList();

   *    SyndCategory category = new SyndCategoryImpl();

   *    category.setName(catName);

   *    categories.add(category);

   *    entry.setCategories(categories);

   *    entries.add(entry);

   *  }

   * @param anArt an article's information

   */

  private void addEntry(ArticleInfo anArt) throws Exception, ParseException {

    int artType = anArt.getTypeID();

    int artID = anArt.getArticleID();

    int parentID = anArt.getParentID();

    String parentName = anArt.getParentArticleName();

    String parentParentName = null;

    int parentType = 0;

    try {

      parentType = myDB.getArtTypeByID(parentID);

      if (parentType == Consts.DIARY_TYPE)

        parentParentName = myDB.getArtNameByID(myDB.getParentIDByID(parentID));

    } catch (Exception e1) {

      e1.printStackTrace();

    }

    String artName = anArt.getArticleName();

    String artAuthor = anArt.getUserName();

    String artContent = anArt.getArticleText();

    String artResource = anArt.getArticleResource();

    String writeDate = anArt.getWriteDate();

    SyndEntry entry = new SyndEntryImpl();

    entry.setAuthor(artAuthor);

    __log.debug("set entry's author is:" + artAuthor);

    entry.setTitle(artName);

    __log.debug("set entry's title is:" + artName);

    //get article's link and rss description head information;

    String link = null, headInfo = null;

    if (artType == Consts.GOAL_TYPE) {

      link =

        Constants.APPLICATION_PATH.concat(

          "/disGoalContentAction.do?goalID=" + artID);

      headInfo =

        "\""

          + artAuthor

          + "\" 在:"

          + writeDate

          + " 首先创建了目标:\""

          + artName

          + "\"<p>";

    } else if (artType == Consts.DIARY_TYPE) {

      link =

        Constants.APPLICATION_PATH.concat(

          "/disDiaryContentAction.do?goalID" + artID);

      headInfo =

        "\""

          + artAuthor

          + "\" 于:"

          + writeDate

          + " 在目标:\""

          + parentName

          + "\"下添加了日记:\""

          + artName

          + "\"<p>";

    } else if (

      artType == Consts.ADVICE_TYPE && parentType == Consts.GOAL_TYPE) {

      link =

        Constants.APPLICATION_PATH.concat(

          "/disGoalContentAction.do?goalID" + parentID);

      headInfo =

        "\""

          + artAuthor

          + "\" 于:"

          + writeDate

          + " 在目标:\""

          + parentName

          + "\"下添加了评论:\""

          + artName

          + "\"<p>";

    } else {

      link =

        Constants.APPLICATION_PATH.concat(

          "/disDiaryContentAction.do?goalID" + parentID);

      headInfo =

        "\""

          + artAuthor

          + "\" 于:"

          + writeDate

          + " 在目标:\""

          + parentParentName

          + "\"的日记:\""

          + parentName

          + "\"下添加了评论:\""

          + artName

          + "\"<p>";

    }

    entry.setLink(link);

    __log.debug("set entry's link is:" + link);

    try {

      entry.setPublishedDate(DATE_PARSER.parse(writeDate));

      __log.debug("set entry's publishedDate is:" + writeDate);

    } catch (ParseException e) {

      e.printStackTrace();

    }

    SyndContent description = new SyndContentImpl();

    description.setType("text/plain");

    String value =

      headInfo.concat("文章内容:<br>").concat(artContent).concat(

        "<p>相关资源:<br>" + artResource);

    description.setValue(value);

    __log.debug("set description's value is:" + value);

    entry.setDescription(description);

    List categories = new ArrayList();

    SyndCategory category = new SyndCategoryImpl();

    category.setName(catName);

    __log.debug("set category's name is:" + catName);

    categories.add(category);

    entry.setCategories(categories);

    entries.add(entry);

    __log.debug(

      "add an entry into entriesList.\n*********************************");

  }

}

  3、

//$ Id: LatestGoalsRSS.java,v 1.0 2006/02/26 20:49:06 dashing_meng Exp $

//Copyright (c) 2004-2005 Http://www.learndiary.com. All Rights Reserved.

//Permission to use, copy, modify, and distribute this software and its

//documentation without fee, and without a written agreement is hereby

//granted, provided that the above copyright notice and this paragraph

//appear in all copies.  This software program and documentation are

//copyrighted by http://www.learndiary.com. The software program and

//documentation are supplied "AS IS", without any accompanying services

//from The LearnDiary. The LearnDiary does not warrant that the operation

//of the program will be uninterrupted or error-free. The end-user

//understands that the program was developed for research purposes and is

//advised not to rely exclusively on the program for any reason.

//IN NO EVENT SHALL HTTP://WWW.LEARNDIARY.COM BE LIABLE TO ANY PARTY FOR

//DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,

//INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS

//DOCUMENTATION, EVEN IF HTTP://WWW.LEARNDIARY.COM HAS BEEN ADVISED OF THE

//POSSIBILITY OF SUCH DAMAGE. HTTP://WWW.LEARNDIARY.COM SPECIFICALLY

//DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE

//SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND

//HTTP://WWW.LEARNDIARY.COM HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,

//SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

package com.learndiary.website.util.rss;

import org.apache.commons.logging.LogFactory;

import com.learndiary.website.Constants;

import com.learndiary.website.Consts;

import com.learndiary.website.dao.TransContext;

import com.learndiary.website.db.ArticleDB;

import com.sun.syndication.feed.synd.SyndFeedImpl;

/**

 * for generating latest goals' rss feed.

 * @author http://www.learndiary.com,LearnDiary Develop Group

 */

public class LatestGoalsRSS extends RSSGenerator {

  public LatestGoalsRSS(String feedType, int entriesNum) {

    this.__log = LogFactory.getFactory().getInstance(this.getClass());

    try {

      RSSGenerator.trans = new TransContext();

      RSSGenerator.myDB = new ArticleDB(trans);

    } catch (Exception e) {

      e.printStackTrace();

    }

    this.feedType = feedType;

    this.entriesNum = entriesNum;

    this.catName = "最新创建的" + entriesNum + "个目标";

  }

  protected void setFeed() throws Exception {

    try {

      this.setEntries("WHERE typeID=1",Consts.ART_WRITE,Consts.DIR_DESC,Consts.HTML_FLAG);

    } catch (Exception e) {

      e.printStackTrace();

    }

    feed = new SyndFeedImpl();

    feed.setFeedType(feedType);

    feed.setTitle("最新创建的" + entriesNum + "个目标");

    feed.setLink(Constants.APPLICATION_PATH.concat("/indexAction.do"));

    feed.setDescription("学习日记里按时间排序的最新创建的" + entriesNum + "个目标。");

    feed.setCopyright(

      "除原作者特别声明外,本站所有帖子以<a rel=\"license\" href=\"http://creativecommons.org/licenses/by/2.0/\" target=\"creativecommons\">Creative Commons License</a>方式授权.");

    feed.setEntries(entries);

  }

}

一个非常成功使用目标分享的语言学习网站http://bulo.hjengl

  http://bulo.hjenglish.com/goal.htm

  我估计这个网站是模仿的www.43things.com的模式。但是,他们把这种模式成功的应用到他们网站的语言学习领域。这个网站的总体运作的模式值得深入研究。

  因为,还需要这种交流形式的网站在未来有可能成为学习日记系统的潜在用户,研究他们的需求是非常有意义的。

一个使用了xml_rpc和 Rome 0.6 for RSS / Atom feed generation开源blog

  他的站点是:https://fatima.dev.java.net/

  下面是简介,我想从中可以学习到相关的知识:

JavaPress: Java Blogging / Content Management System

This software is a content management system that runs in a Jakarta Tomcat container with AJAX additions.

Because it runs in Java, it provides a good alternative to the many PHP containers out there. From the technology perspective, it has custom category management, and category exclusion like Slashdot, Rome 0.5 API(s) from Sun Microsystems provides RSS 2.0, 1.x, and Atom x.3 feeds as well as auto generating feeds for each category and can generate Podcasts using the tag. It also has automated XML-RPC pinging using Apache's XML-RPC libraries and can ping up to 50 sites with custom categories (i.e. you can ping javablogs.com with only your "Java" category RSS feed if you wish). It also has a complete user management area where users can edit or delete their comments and manage their information, something lacking in other blogging software. It also includes internal messaging and email notification using JavaMail. It has a custom admin section as well to manage all aspects of the code, and can run on MySQL, PostgreSQL, or any XML JDBC interface using connection pooling. It also uses Hibernate for many Java Beans.

The project is delivered in two sections:

PressCore - The EAR file, although it can be simply deployed as classes in the WEB-INF/classes folder, contains all the workhorse code, including the Technorati integration, Hibernate code, Connection Pooling, JNDI, category management and exclusion, rss generation, podcasting manager, xml-rpc pinging (up to 40 sites now, database driven!) and many other neat things.

PressWeb - The WAR file as it were, or simply the content with the JSP tags and example WEB-INF and META-INF that implements all the db pooling, mailing and other features. Should be easy to set up if you use the /install directory after you deploy this WAR in your Tomcat container (WARNING: Delete this install directory before you release in to production!)

External API(s):

Sun Microsystem's Rome 0.6 for RSS / Atom feed generation

Apache XML-RPC libraries for weblog pinging

Sun Microsystem's Java API for XML Processing (JAXP) v1.2.6_01

Sun Microsystem's JavaServer Pages Standard Tag Library (JSTL) v1.1.1_01

Technorati Java API (jTechnorati)

学习日记站内检索的范围应该覆盖每篇帖子

  目前,学习日记的检索只包括了“目标”和“日记”,而有不少有价值的帖子还在评论里,虽然可以借助搜索引擎完成,但是,毕竟,搜索引擎的东西不实时,而且还有收录不到的地方,例如:我以"目标" "毕竟" "分享" site:www.learndiary.com为关键字在站内google时就找不到帖子:http://www.learndiary.com/disGoalContentAction.do?goalID=1287&naviStr=a10ag505 ,在百度中以上述关键字"目标" "毕竟" "分享" site:www.learndiary.com可以找到,但是,肯定还是百度也找不到的中文网页。所以应该检索目标包括对目标相应的评论,检索日记包括对日记相应的评论。

目标和日记需要增加公开性分级

  正如一位朋友javar所说:“毕竟有一些可能不想和大家分享的东西”,见:http://www.learndiary.com/disGoalContentAction.do?goalID=1287&naviStr=a10ag505

标题: 20051129 第二贴  作者: javar  创建时间: 2005-11-29 10:49:25  最近更新: 2005-11-29 10:49:25  编辑 

内容

说说个人对这个站点的一些建议:

1.自己的目标是不是可以添加公开和隐私两种状态,毕竟有一些可能不想和大家分享的东西;

2.网站的界面个人感觉需要美化一下,感觉怪怪的。

3.既然叫日记了,建议在首页添加一个日历,让大家可以按日期来查看当天的更新。

暂时想到这么多,孤妄写之。 

相关资源 

标题: 谢谢javar ,您的建议很好,计划中...  作者: littlebat  创建时间: 2005-11-29 14:45:51  最近更新: 2005-11-29 14:45:51  编辑 

内容

>1.自己的目标是不是可以添加公开和隐私两种状态,毕竟有一些可能不想和大家分享的东西;

还可以添加供朋友加入的目标,也可以邀请朋友加入自己的目标;

>2.网站的界面个人感觉需要美化一下,感觉怪怪的。

我们最初的打算是功能优先,界面随后。仿www.delphibbs.com风格;

>3.既然叫日记了,建议在首页添加一个日历,让大家可以按日期来查看当天的更新。

实际我们的运作方式类似于blog,确实可以添加日历。以后可能考虑提供两种风格供用户定制:BBS风格、BLOG风格。

再次衷心感谢javar的中肯的建议。

祝愿我们共同学习、进步! 

动态输出网站的文章(以xml格式),定期发布网站数据库

  为了方便朋友再加工自己的文章,和方便朋友使用本站的资料,可以添加动态输出xml格式的网站文章的功能。例如:一篇日记及其所有评论,一个目标及其所有日记、评论,用户加入的目标的所有自己的日记和相应的评论...。

  定期发布网站的数据库,可以仿照delphibbs.com(大富翁)的做法,以后开发一款学习日记自己的离线浏览器。