使用WebWork和Rome轻松暴露RSS

阅读更多

WebWork的result实现非常实用,它很好的解决了View渲染的灵活性问题。这才是MVC模式的优势所在,而像JSF那样帮定JSP的MVC就吃不到这个甜头了。说WebWork2是Model 2 MVC的巅峰就在这些灵活的地方。
闲扯这个不是主要目的。现在Rome是Java下最常用的RSS包,最近消息似乎要转入Apache的Abdera合并变成更强大的聚合引擎。用Rome生成和解析RSS都很方便。今天讨论一下使用ROME给网站生成RSS,并通过WebWork2的Result机制渲染。
最初是从WebWork的Cookbook上看到的RomeResult的文章,一看就会,我这里其实不过是举个详细点的例子,注意我使用的是WebWork 2.2.2和Rome 0.8:
http://wiki.opensymphony.com/display/WW/RomeResult
参考了和东的这篇Blog,利用rome写rss feed生成程序:
http://hedong.3322.org/newblog/archives/000051.html

首先创建RomeResult类:

/**
 * 
 
*/
package  com.goldnet.framework.webwork.result;

import  java.io.Writer;

import  org.apache.log4j.Logger;

import  com.opensymphony.webwork.ServletActionContext;
import  com.opensymphony.xwork.ActionInvocation;
import  com.opensymphony.xwork.Result;
import  com.sun.syndication.feed.synd.SyndFeed;
import  com.sun.syndication.io.SyndFeedOutput;

/**
 * A simple Result to output a Rome SyndFeed object into a newsfeed.
 * 
@author  Philip Luppens
 * 
 
*/
public   class  RomeResult  implements  Result {
 
private   static   final   long  serialVersionUID  =   - 6089389751322858939L ;

 
private  String feedName;

 
private  String feedType;

 
private   final   static  Logger logger  =  Logger.getLogger(RomeResult. class );

 
/*
  * (non-Javadoc)
  * 
  * @see com.opensymphony.xwork.Result#execute(com.opensymphony.xwork.ActionInvocation)
  
*/
 
public   void  execute(ActionInvocation ai)  throws  Exception {
  
if  (feedName  ==   null ) {
   
//  ack, we need this to find the feed on the stack
   logger
     .error(
" Required parameter 'feedName' not found.  "
       
+   " Make sure you have the param tag set and  "
       
+   " the static-parameters interceptor enabled in your interceptor stack. " );
   
//  no point in continuing ..
    return ;
  }

  
//  don't forget to set the content to the correct mimetype
  ServletActionContext.getResponse().setContentType( " text/xml " );
  
//  get the feed from the stack that can be found by the feedName
  SyndFeed feed  =  (SyndFeed) ai.getStack().findValue(feedName);

  
if  (logger.isDebugEnabled()) {
   logger.debug(
" Found object on stack with name ' "   +  feedName  +   " ':  "
     
+  feed);
  }
  
if  (feed  !=   null ) {

   
if  (feedType  !=   null ) {
    
//  Accepted types are: rss_0.90 - rss_2.0 and atom_0.3
    
//  There is a bug though in the rss 2.0 generator when it checks
    
//  for the type attribute in the description element. It's has a
    
//  big 'FIXME' next to it (v. 0.7beta).
    feed.setFeedType(feedType);
   }
   SyndFeedOutput output 
=   new  SyndFeedOutput();
   
// we'll need the writer since Rome doesn't support writing to an outputStream yet
   Writer out  =   null ;
   
try  {
    out 
=  ServletActionContext.getResponse().getWriter();
    output.output(feed, out);
   } 
catch  (Exception e) {
    
//  Woops, couldn't write the feed ?
    logger.error( " Could not write the feed " , e);
   } 
finally  {
    
// close the output writer (will flush automatically)
     if  (out  !=   null ) {
     out.close();
    }
   }

  } 
else  {
   
//  woops .. no object found on the stack with that name ?
   logger.error( " Did not find object on stack with name ' "   +  feedName
     
+   " ' " );
  }
 }

 
public   void  setFeedName(String feedName) {
  
this .feedName  =  feedName;
 }

 
public   void  setFeedType(String feedType) {
  
this .feedType  =  feedType;
 }

}

程序很简单。实现了Result接口,寻找一个与feedName参数匹配的SyndFeed实例,然后转换为指定的feedType类型,然后通过rome的SyndFeedOutput输出到Response去。
然后我们给我们的WebWork配置romeResult。
在xwork.xml中配置:

< package  name ="default"  extends ="webwork-default" >
  
< result-types >
   
< result-type  name ="feed"  class ="com.goldnet.framework.webwork.result.RomeResult" />
  
result-types >
  
< interceptors >
  

这样我们就给xwork配置了一个叫做feed的result,它就是我们的romeResult。
然后我们实现一个类,来测试一下这个romeResult。

/**
 *
 
*/
package  com.goldnet.webwork.action.news;

import  com.opensymphony.xwork.ActionSupport;

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.feed.synd.SyndFeedImpl;

import  org.apache.commons.logging.Log;
import  org.apache.commons.logging.LogFactory;

import  java.util.ArrayList;
import  java.util.Date;
import  java.util.List;


/**
 * 
@author  Tin
 *
 
*/
public   class  TestFeedCreateAction  extends  ActionSupport {
    
private   static   final   long  serialVersionUID  =   - 2207516408313865979L ;
    
private   transient   final  Log log  =  LogFactory.getLog(TestFeedCreateAction. class );
    
private   int  maxEntryNumber  =   25 ;
    
private  String siteUrl  =   " http://127.0.0.1 " ;
    
private  SyndFeed feed  =   null ;

    
public  TestFeedCreateAction() {
        
super ();
    }

    @Override
    
public  String execute() {
        List
< News >  newsList  =  getNewsList();

        
if  (log.isDebugEnabled()) {
            log.debug(
" Geting feed! and got news  "   +  newsList.size()  +
                
"  pieces. " );
        }

        feed 
=   new  SyndFeedImpl();

        feed.setTitle(converttoISO(
" 测试中的新闻系统 " ));
        feed.setDescription(converttoISO(
" 测试中的新闻系统:测试Rome Result " ));
        feed.setAuthor(converttoISO(
" 测试Tin " ));
        feed.setLink(
" http://www.justatest.cn " );

        List
< SyndEntry >  entries  =   new  ArrayList < SyndEntry > ();
        feed.setEntries(entries);

        
for  (News news : newsList) {
            SyndEntry entry 
=   new  SyndEntryImpl();
            entry.setAuthor(converttoISO(news.getAuthor()));

            SyndCategory cat 
=   new  SyndCategoryImpl();
            cat.setName(converttoISO(news.getCategory()));

            List
< SyndCategory >  cats  =   new  ArrayList < SyndCategory > ();
            cats.add(cat);
            entry.setCategories(cats);

            SyndContent content 
=   new  SyndContentImpl();
            content.setValue(converttoISO(news.getContent()));

            List
< SyndContent >  contents  =   new  ArrayList < SyndContent > ();
            contents.add(content);
            entry.setContents(contents);
            entry.setDescription(content);
            entry.setLink(siteUrl 
+   " /common/news/displayNews.action?id= "   +
                news.getId());
            entry.setTitle(converttoISO(news.getTitle()));
            entry.setPublishedDate(news.getPublishDate());
            entries.add(entry);
        }

        
return  SUCCESS;
    }

    
private   static  String converttoISO(String s) {
        
try  {
            
byte [] abyte0  =  s.getBytes( " UTF-8 " );

            
return   new  String(abyte0,  " ISO-8859-1 " );
        } 
catch  (Exception exception) {
            
return  s;
        }
    }

    
private  List < News >  getNewsList() {
        List
< News >  newsList  =   new  ArrayList < News > ();

        
for  ( int  i  =   0 ; i  <  maxEntryNumber; i ++ ) {
            News news 
=   new  News();
            news.setTitle(
" 测试标题 "   +  i);
            news.setContent(
                
"

测试内容测试内容 " color:red\ " >测试内容

" );
            news.setPublishDate(
new  Date());
            news.setId(
new  Long(i));
            news.setAuthor(
" Tin " );
            newsList.add(news);
        }

        
return  newsList;
    }

    
/**
     * 
@return  Returns the maxEntryNumber.
     
*/
    
public   long  getMaxEntryNumber() {
        
return  maxEntryNumber;
    }

    
/**
     * 
@param  maxEntryNumber The maxEntryNumber to set.
     
*/
    
public   void  setMaxEntryNumber( int  maxEntryNumber) {
        
this .maxEntryNumber  =  maxEntryNumber;
    }

    
/**
     * 
@param  siteUrl The siteUrl to set.
     
*/
    
public   void  setSiteUrl(String siteUrl) {
        
this .siteUrl  =  siteUrl;
    }

    
/**
     * 
@return  Returns the feed.
     
*/
    
public  SyndFeed getFeed() {
        
return  feed;
    }

    
private   class  News {
        
private  Long id;
        
private  String title;
        
private  String content;
        
private  Date publishDate;
        
private  String author;
        
private  String category;

        
/**
  * Getter/Setter都省略了,使用了内部类,就是图个方便
  * 本意是模仿我们常常使用的Pojo,大家的实现都不一样,我突简单,里面其实可以有复杂类型的
  
*/
    }
}

真是不好意思,Getter/Setter占了大部分地方我省略去了。逻辑很简单,就是把我们的POJO影射到Feed的模型上面,过程很简单。我留下了几个参数可以在外面设置:
maxEntryNumber显示的feed的条数,链接生成时使用的SiteUrl,当然也可以通过request获取。
下面我们配置我们的Action,注意平时我们可能使用DAO生成newsList,而不是我这个写死的getNewsList()方法,此时可能需要配合Spring进行IOC的设置,我们这里省略掉。
下面是我们这个Action的xwork配置:

< package  name ="news"  extends ="default"  namespace ="/news" >
  
< action  name ="feed"  class ="com.goldnet.webwork.action.news.TestFeedCreateAction" >
   

   
< param  name ="maxEntryNumber" > 15 param >
   

   
< param  name ="siteUrl" > http://127.0.0.1:7001 param >
   

   
< result  name ="success"  type ="feed" >
    

    
< param  name ="feedName" > feed param >
    

    

    
< param  name ="feedType" > rss_2.0 param >
   
result >
  
action >
package >

OK,配置完毕后访问/news/feed.action就可以访问到这个feed了。倒入你的feedDeamon,看看,是不是非常简单?
不过需要考虑两个地方,一个是编码问题,看了和东说的中文问题,本没当回事,结果生成乱码(我们项目全部使用UTF-8),然后还是转了一下。没有研究ROME源代码,感觉xml不应该有UTF-8还会乱码的问题呀,也许还需要看看是否是设置不到位。还有就是对于feed如果增加了权限认证则访问比较麻烦,用feedDeamon这样的客户端就无法访问到了,因为它不会显示登陆失败后显示的登陆页面,也许放feed就要开放一点吧(当然还是有变通放案的)。
和动例子里面的rome 0.7和现在的rome 0.8相比,Api已经发生了不少变化,唉,开源要代码稳定还真难。
就这些,就到这里,粗陋了:D

你可能感兴趣的:(Webwork,SUN,MVC,Apache,Spring)