WebWork的result實(shí)現(xiàn)非常實(shí)用,它很好的解決了View渲染的靈活性問(wèn)題。這才是MVC模式的優(yōu)勢(shì)所在,而像JSF那樣幫定JSP的MVC就吃不到這個(gè)甜頭了。說(shuō)WebWork2是Model 2 MVC的巔峰就在這些靈活的地方。
閑扯這個(gè)不是主要目的。現(xiàn)在Rome是Java下最常用的RSS包,最近消息似乎要轉(zhuǎn)入Apache的Abdera合并變成更強(qiáng)大的聚合引擎。用Rome生成和解析RSS都很方便。今天討論一下使用ROME給網(wǎng)站生成RSS,并通過(guò)WebWork2的Result機(jī)制渲染。
最初是從WebWork的Cookbook上看到的RomeResult的文章,一看就會(huì),我這里其實(shí)不過(guò)是舉個(gè)詳細(xì)點(diǎn)的例子,注意我使用的是WebWork 2.2.2和Rome 0.8:
http://wiki.opensymphony.com/display/WW/RomeResult
參考了和東的這篇Blog,利用rome寫(xiě)rss feed生成程序:
http://hedong.3322.org/newblog/archives/000051.html
首先創(chuàng)建RomeResult類(lèi):
?*?
? */
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;
?}
}
程序很簡(jiǎn)單。實(shí)現(xiàn)了Result接口,尋找一個(gè)與feedName參數(shù)匹配的SyndFeed實(shí)例,然后轉(zhuǎn)換為指定的feedType類(lèi)型,然后通過(guò)rome的SyndFeedOutput輸出到Response去。
然后我們給我們的WebWork配置romeResult。
在xwork.xml中配置:






這樣我們就給xwork配置了一個(gè)叫做feed的result,它就是我們的romeResult。
然后我們實(shí)現(xiàn)一個(gè)類(lèi),來(lái)測(cè)試一下這個(gè)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( " 測(cè)試中的新聞系統(tǒng) " ));
????????feed.setDescription(converttoISO( " 測(cè)試中的新聞系統(tǒng):測(cè)試Rome?Result " ));
????????feed.setAuthor(converttoISO( " 測(cè)試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( " 測(cè)試標(biāo)題 " ? + ?i);
????????????news.setContent(
???????????????? " <p>測(cè)試內(nèi)容測(cè)試內(nèi)容<span?style=\ " color:red\ " >測(cè)試內(nèi)容</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都省略了,使用了內(nèi)部類(lèi),就是圖個(gè)方便
??*?本意是模仿我們常常使用的Pojo,大家的實(shí)現(xiàn)都不一樣,我突簡(jiǎn)單,里面其實(shí)可以有復(fù)雜類(lèi)型的
?? */
????}
}
真是不好意思,Getter/Setter占了大部分地方我省略去了。邏輯很簡(jiǎn)單,就是把我們的POJO影射到Feed的模型上面,過(guò)程很簡(jiǎn)單。我留下了幾個(gè)參數(shù)可以在外面設(shè)置:
maxEntryNumber顯示的feed的條數(shù),鏈接生成時(shí)使用的SiteUrl,當(dāng)然也可以通過(guò)request獲取。
下面我們配置我們的Action,注意平時(shí)我們可能使用DAO生成newsList,而不是我這個(gè)寫(xiě)死的getNewsList()方法,此時(shí)可能需要配合Spring進(jìn)行IOC的設(shè)置,我們這里省略掉。
下面是我們這個(gè)Action的xwork配置:
















OK,配置完畢后訪問(wèn)/news/feed.action就可以訪問(wèn)到這個(gè)feed了。倒入你的feedDeamon,看看,是不是非常簡(jiǎn)單?
不過(guò)需要考慮兩個(gè)地方,一個(gè)是編碼問(wèn)題,看了和東說(shuō)的中文問(wèn)題,本沒(méi)當(dāng)回事,結(jié)果生成亂碼(我們項(xiàng)目全部使用UTF-8),然后還是轉(zhuǎn)了一下。沒(méi)有研究ROME源代碼,感覺(jué)xml不應(yīng)該有UTF-8還會(huì)亂碼的問(wèn)題呀,也許還需要看看是否是設(shè)置不到位。還有就是對(duì)于feed如果增加了權(quán)限認(rèn)證則訪問(wèn)比較麻煩,用feedDeamon這樣的客戶端就無(wú)法訪問(wèn)到了,因?yàn)樗粫?huì)顯示登陸失敗后顯示的登陸頁(yè)面,也許放feed就要開(kāi)放一點(diǎn)吧(當(dāng)然還是有變通放案的)。
和動(dòng)例子里面的rome 0.7和現(xiàn)在的rome 0.8相比,Api已經(jīng)發(fā)生了不少變化,唉,開(kāi)源要代碼穩(wěn)定還真難。
就這些,就到這里,粗陋了:D