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中配置:
< 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配置:
< 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