Tin's Blog

You are coming a long way, baby~Thinking, feeling, memory...

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  128 随笔 :: 0 文章 :: 221 评论 :: 0 Trackbacks

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 >
  
<!--  然后是你的那些inteceptor配置等  -->

这样我们就给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(
                
" <p>测试内容测试内容<span style=\ " color:red\ " >测试内容</span></p> " );
            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" >
   
<!--  每次生成15条rss feed  -->
   
< param  name ="maxEntryNumber" > 15 </ param >
   
<!--  链接的前缀,我们使用Weblogic是7001,也许你的是8080  -->
   
< param  name ="siteUrl" > http://127.0.0.1:7001 </ param >
   
<!--  result是feed  -->
   
< result  name ="success"  type ="feed" >
    
<!--  feed名字是feed,对应我们这个Action中的那个SyndFeed的实例的名字feed,别忘记写getter  -->
    
< param  name ="feedName" > feed </ param >
    
<!--  制定生成的feed的类型,我这里选择rss_2.0  -->
    
<!--  rome 0.8支持atom_0.3、atom_1.0、rss_1.0、rss_2.0、rss_0.90、rss_0.91、rss_0.91、rss_0.91U、rss_0.92、rss_0.93、rss_0.94  -->
    
< 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

posted on 2006-06-05 22:25 Tin 阅读(3375) 评论(7)  编辑  收藏 所属分类: Webwork相关

评论

# re: 使用WebWork和Rome轻松暴露RSS 2006-06-06 08:59 wolfsquare
不错,赞一个.
这样的文章比整天鼓噪自己的开源项目和团队还在首页吵架的文章要好多了.
  回复  更多评论
  

# re: 使用WebWork和Rome轻松暴露RSS 2006-06-07 00:54 差沙
写的很好呀,赞一个。厚厚。  回复  更多评论
  

# re: 使用WebWork和Rome轻松暴露RSS 2006-07-11 18:50 Border
怎么解决中文编码问题,现在已经调试成功,但是当有中文就出现一部分乱码,不知道怎么解决。不知道你是怎么解决的,能不能给些建议。
先谢过了

  回复  更多评论
  

# re: 使用WebWork和Rome轻松暴露RSS 2006-07-11 22:15 Tin
如果只有部分中文乱码,可能是使用了GBK编码,转换为UTF-8等编码时会有部分字符无法转换吧。你从GBK转到ISO8850-1看看。  回复  更多评论
  

# re: 使用WebWork和Rome轻松暴露RSS 2006-07-12 09:55 Border
还是不行,我的原feed文件是utf-8的,也就是你的rss文件,http://www.blogjava.net/iamtin/Rss.aspx
要是我GBK转到ISO8859-1还是乱码,我只有通过
entry.setTitle(new String(entry.getTitle().getBytes("utf-8")));
来把原feed文件,方到目标文件,不过还是出现部分乱码。如果方便的话,我把我的代码给你发过去,你看看。

borderj#gmail.com

  回复  更多评论
  

# re: 使用WebWork和Rome轻松暴露RSS 2006-09-25 17:39 feiyi10
我开始也出现了中文乱码问题。。跟踪发现,其实跟set的时候没关系。
之所以出现乱码问题。是因为RomeResult这个类默认编码为ISO8859-1。
在ServletActionContext.getResponse().setContentType( " text/xml " );出加一句ServletActionContext.getResponse().setCharacterEncoding("utf-8");//根据需要添写自己的编码。希望对大家有所帮助。说的不对。还望见谅。  回复  更多评论
  

# re: 使用WebWork和Rome轻松暴露RSS 2006-09-25 18:14 Tin
谢谢feiyi10提醒。估计是response的编码设置问题,我没有认真跟踪。希望遇到问题的朋友尝试一下。  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问