GXT之旅:第四章:Data与Components(3)——Server端的持久化(1)

小妹大年初四上班,发博啦害羞害羞害羞害羞可怜可怜可怜可怜

Server端的持久化

到目前为止,在RSSReader项目里,还没有任何持久化的操作。为了让我们项目更具有真实性,现在我们要添加持久化的代码。但是为了让我们更专注于client-side,持久化的逻辑仅仅是最基本的操作——实现真实的持久化逻辑之前先加入持久化的接口,这样就可以为了需要,可以在不改变接口调用的基础上,改用另外一种持久化操作的内容既可(比如hibernate)。

目前,实现最初的持久化版本,步骤如下:

  • 当添加新的feed实体时候,在server-side使用xml文件来存储。
  • xml文件只有一个,我们会在这个文件里维护feed的列表。

持久化的代码不属于GXT的犯愁,因此我们可以把他以一个黑盒对待。在我们RSSReader项目里,要加入Persistence接口和实现此接口的FilePersistence类,他们的功能就是负责存储和获得RSS feed信息的。


持久化一个存在的Feed

在第二章,我们新建一个Link feed button,目的是用来从internet里导入一个已经存在的RSS feed网络地址。接下来我们要在FeedService接口里,定义addExistingFeed方法,用作持久层存储RSS feed的URL地址。此功能要被绑定到LinkFeedPopup的add button上。

  • 在FeedService接口里,定义addExistingFeed方法,当然要传入一个URL 参数

void addExistingFeed(String feedUrl);

  • 同样的会在FeedServiceAsync接口里,定义与之相关的异步回调方法

void addExistingFeed(String feedUrl, AsyncCallback<Void>
callback);

  • 修改LinkFeedPopup的addFeed方法,加入addExistingFeed回调方法的调用,具体逻辑一看便知

	public void addFeed(final String feedUrl) {
		final FeedServiceAsync feedService = Registry
				.get(RSSReaderConstants.FEED_SERVICE);
		feedService.addExistingFeed(feedUrl, new AsyncCallback<Void>() {
			@Override
			public void onFailure(Throwable caught) {
				Info.display("RSS Reader", "Failed to add feed at: " + feedUrl);
			}

			@Override
			public void onSuccess(Void result) {
				tfUrl.clear();
				Info.display("RSS Reader", "Feed at " + feedUrl
						+ " added successfully");
				hide();
			}
		});
	}


  • FeedServiceImpl类里,我们要加入日志,这里用简单的java.util.logging.Logger

	private final static Logger LOGGER = Logger.getLogger(FeedServiceImpl.class
			.getName());

  • 在FeedServiceImpl类里,加入private的方法loadFeed,用来根据feed的URL,在JDOM规范下,从internet里获得RSS的XML内容,返回Feed实体bean

	private Feed loadFeed(String feedUrl) {
		Feed feed = new Feed(feedUrl);
		try {
			SAXBuilder parser = new SAXBuilder();
			Document document = parser.build(new URL(feedUrl));
			Element eleRoot = document.getRootElement();
			Element eleChannel = eleRoot.getChild("channel");
			feed.setTitle(eleChannel.getChildText("title"));
			feed.setDescription(eleChannel.getChildText("description"));
			feed.setLink(eleChannel.getChildText("link"));
			return feed;
		} catch (IOException e) {
			LOGGER.log(Level.SEVERE, "IO Error loading feed", e);
			return feed;
		} catch (JDOMException e) {
			LOGGER.log(Level.SEVERE, "Error parsing feed", e);
			return feed;
		}
	}

  • 在FeedServiceImpl类里,加入HashMap的属性,用来存储Feed对象

private Map<String, Feed> feeds = new HashMap<String, Feed>();

  • 我们目前的持久化功能是依赖与jdom-1.1.2.jar包功能的实现,具体的持久化代码如下,全部贴出来
持久化的配置文件:rssreader.properties(放在src\下)
feed.file=feeds.txt
data.folder=data
base.url=http://127.0.0.1:8888


package com.danielvaughan.rssreader.server.utils;

import java.util.Set;

import org.jdom.Document;

public interface Persistence {

	public Set<String> loadFeedList();

	public void saveFeedList(Set<String> feedUrls);
	
	public void saveFeedXml(String uuid, Document document);

	public String getUrl(String uuid);
}

package com.danielvaughan.rssreader.server.utils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Logger;

import org.jdom.Document;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

public class FilePersistence implements Persistence {

	private final static Logger LOGGER = Logger.getLogger(FilePersistence.class
			.getName());

	private String dataFolder;
	private String feedFilePath;
	private String baseUrl;

	private final Properties properties = new Properties();

	public FilePersistence() {
		// Read properties file.
		try {
			ClassLoader loader = ClassLoader.getSystemClassLoader();
			InputStream in = loader.getResourceAsStream("rssreader.properties");
			properties.load(in);

			dataFolder = (String) properties.get("data.folder");
			String feedFile = (String) properties.get("feed.file");
			feedFilePath = dataFolder + "\\" + feedFile;
			baseUrl = (String) properties.get("base.url");

			initDataFolder();
		} catch (IOException e) {
			LOGGER.severe("Unable to load properties file");
		}
	}

	private void initDataFolder() {
		try {
			File dataFolderFile = new File(dataFolder);
			if (!dataFolderFile.exists()) {
				dataFolderFile.mkdir();
			}
			File feedFile = new File(feedFilePath);
			if (!feedFile.exists()) {
				feedFile.createNewFile();
			}
		} catch (IOException e) {
			LOGGER.severe("Error initialising data folder");
		}
	}

	@Override
	public void saveFeedList(Set<String> feedUrls) {
		try {
			FileWriter fileWriter = new FileWriter(feedFilePath);
			BufferedWriter out = new BufferedWriter(fileWriter);
			for (String feedUrl : feedUrls) {
				String line = feedUrl.concat("\n");
				out.write(line);
			}
			out.close();
		} catch (Exception e) {
			LOGGER.severe("Error: " + e.getMessage());
		}
	}

	@Override
	public Set<String> loadFeedList() {
		Set<String> feedUrls = new HashSet<String>();
		try {
			FileInputStream fstream = new FileInputStream(feedFilePath);
			DataInputStream in = new DataInputStream(fstream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String strLine;
			while ((strLine = br.readLine()) != null) {
				feedUrls.add(strLine);
			}
			in.close();
			return feedUrls;
		} catch (Exception e) {
			LOGGER.severe("Error: " + e.getMessage());
			return feedUrls;
		}
	}

	@Override
	public void saveFeedXml(String feedId, Document document) {
		try {
			File file = new File(generateFilePath(feedId));
			XMLOutputter serializer = new XMLOutputter();
			Format prettyFormat = Format.getPrettyFormat();
			serializer.setFormat(prettyFormat);
			FileWriter writer = new FileWriter(file);
			serializer.output(document, writer);
			writer.close();
		} catch (IOException e) {
			LOGGER.severe("Error: " + e.getMessage());
		}
	}

	private String generateFilePath(String feedId) {
		return dataFolder + "/" + feedId + ".xml";
	}

	@Override
	public String getUrl(String feedId) {
		String fileName = generateFilePath(feedId);
		return baseUrl + "/" + fileName;
	}
}


  • 最后在FeedServiceImpl类里,实现addExistingFeed方法,调用刚才创建的loadFeed方法,根据feedUrl返回Feed对象,再调用上面持久化类的saveFeedList方法,完成持久化操作

	@Override
	public void addExistingFeed(String feedUrl) {
		Feed loadResult = loadFeed(feedUrl);
		if (loadResult.getTitle() != null) {
			feeds.put(feedUrl, loadFeed(feedUrl));
			persistence.saveFeedList(feeds.keySet());
		}
	}

  • 创建本地的RSS xml文件用来读取:http://127.0.0.1:8888/rss2sample.xml。在WebContent\下创建rss2sample.xml,内容如下:
<?xml version="1.0"?>
<rss version="2.0">
   <channel>
      <title>Liftoff News</title>
      <link>http://liftoff.msfc.nasa.gov/</link>
      <description>Liftoff to Space Exploration.</description>
      <language>en-us</language>
      <pubDate>Tue, 10 Jun 2003 04:00:00 GMT</pubDate>

      <lastBuildDate>Tue, 10 Jun 2003 09:41:01 GMT</lastBuildDate>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs>
      <generator>Weblog Editor 2.0</generator>
      <managingEditor>editor@example.com</managingEditor>
      <webMaster>webmaster@example.com</webMaster>
      <item>

         <title>Star City</title>
         <link>http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asp</link>
         <description>How do Americans get ready to work with Russians aboard the International Space Station? They take a crash course in culture, language and protocol at Russia's <a href="http://howe.iki.rssi.ru/GCTC/gctc_e.htm">Star City</a>.</description>
         <pubDate>Tue, 03 Jun 2003 09:39:21 GMT</pubDate>
         <guid>http://liftoff.msfc.nasa.gov/2003/06/03.html#item573</guid>

      </item>
      <item>
         <description>Sky watchers in Europe, Asia, and parts of Alaska and Canada will experience a <a href="http://science.nasa.gov/headlines/y2003/30may_solareclipse.htm">partial eclipse of the Sun</a> on Saturday, May 31st.</description>
         <pubDate>Fri, 30 May 2003 11:06:42 GMT</pubDate>
         <guid>http://liftoff.msfc.nasa.gov/2003/05/30.html#item572</guid>

      </item>
      <item>
         <title>The Engine That Does More</title>
         <link>http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp</link>
         <description>Before man travels to Mars, NASA hopes to design new engines that will let us fly through the Solar System more quickly.  The proposed VASIMR engine would do that.</description>
         <pubDate>Tue, 27 May 2003 08:37:32 GMT</pubDate>
         <guid>http://liftoff.msfc.nasa.gov/2003/05/27.html#item571</guid>

      </item>
      <item>
         <title>Astronauts' Dirty Laundry</title>
         <link>http://liftoff.msfc.nasa.gov/news/2003/news-laundry.asp</link>
         <description>Compared to earlier spacecraft, the International Space Station has many luxuries, but laundry facilities are not one of them.  Instead, astronauts have other options.</description>
         <pubDate>Tue, 20 May 2003 08:56:02 GMT</pubDate>
         <guid>http://liftoff.msfc.nasa.gov/2003/05/20.html#item570</guid>

      </item>
   </channel>
</rss>



  • 运行程序,会读取rssreader.properties配置文件初始化持久化的配置。当你通过Link feed button 成功添加一个真实的URL link(http://127.0.0.1:8888/rss2sample.xml)的时候,会在项目WebContent\data\feeds.txt文件里存储一行内容http://127.0.0.1:8888/rss2sample.xml







评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值