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配置等 -->
然后我們實現一個類,來測試一下這個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> newnewsList = new ArrayList<News>();
- for (int i = 0; i < maxEntryNumber; i++) {
- News newnews = 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
摘自:http://www.javaeye.com/post/125096