持久化与Store的同步
还记得之前,我们实现了,通过client side的缓存store(ListStore)存储feed对象集合。但是那仅仅是在缓存里面存储着,并没有持久化数据。还记得当时是通过GWT RPC调用saveFeed方法,仅仅是将要保存的feed对象发送到server side,仅仅是按照xml格式转换之后打印出来,并没有持久化。只要应用程序一重启,所有的store都会随即消失。
接下来,我们就要重新编写saveFeed方法,加入持久化的功能,当持久化操作成功之后,再同步到对应的Store里。
- FeedServiceImpl类里,取出掉先前的XML序列化代码。取而代之的是调用Persistence接口的saveFeedXml方法,用于持久化的处理。
public void saveFeed(Feed feed) {
Element eleRoot = new Element("rss");
eleRoot.setAttribute(new Attribute("version", "2.0"));
// Create a document from the feed object
Document document = new Document(eleRoot);
Element eleChannel = new Element("channel");
Element eleTitle = new Element("title");
Element eleDescription = new Element("description");
Element eleLink = new Element("link");
eleTitle.setText(feed.getTitle());
eleDescription.setText(feed.getDescription());
eleLink.setText(feed.getLink());
eleChannel.addContent(eleTitle);
eleChannel.addContent(eleDescription);
eleChannel.addContent(eleLink);
eleRoot.addContent(eleChannel);
persistence.saveFeedXml(feed.getUuid(), document);
addExistingFeed(persistence.getUrl(feed.getUuid()));
}
- 调用addExistingFeed(persistence.getUrl(feed.getUuid()));将新生成的持久化xml文件的网络地址返回给addExistingFeed方法,将其保存到feeds.txt 列表里。
- 运行应用程序,在弹出的feed窗口里,录入feed相关信息,点击保存 save button。
- 添加成功之后,首先在navigation导航去马上显示出来,说明store已经有变化了。
- 最后,查看持久化的文件(WebContent\data\)是否成功生成,并且将其url加到feeds.txt 列表里。
Server端持久化数据load
当feeds已经成功的在server端持久化之后,我们需要让RSSReader项目在重新启动之后,可以重新检索出所有的feed信息,并加载显示出来。因此,接下来需要在FeedService接口里,添加一个loadFeedList方法。功能是读取feeds.txt持久化文件里面所有的url集合,将其存储在client side的store当中。- 在FeedService接口里加入loadFeedList方法
List<Feed> loadFeedList();
- 同样的,要添加异步回调方法(FeedServiceAsync接口)
void loadFeedList(AsyncCallback<List<Feed>> callback);
- 在FeedServiceImpl类实现loadFeedList方法:通过调用Persistence接口里的loadFeedList方法,返回feed url结果集,然后遍历结果集,根据每个url加载其feed内容,存储在HashMap feeds里。
@Override
public List<Feed> loadFeedList() {
feeds.clear();
Set<String> feedUrls = persistence.loadFeedList();
for (String feedUrl : feedUrls) {
feeds.put(feedUrl, loadFeed(feedUrl));
}
return new ArrayList<Feed>(feeds.values());
}
- 重新编写FeedList类,让程序启动的时候调用loadfeedList方法,从持久化的文件,检索出内容,存储到store当中去,让FeedList component显示出来store 的内容。整个代码如下:
package com.danielvaughan.rssreader.client.lists;
import java.util.List;
import com.danielvaughan.rssreader.client.RSSReaderConstants;
import com.danielvaughan.rssreader.client.services.FeedServiceAsync;
import com.danielvaughan.rssreader.shared.model.Feed;
import com.danielvaughan.rssreader.shared.model.Item;
import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.data.BaseListLoader;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.BeanModelFactory;
import com.extjs.gxt.ui.client.data.BeanModelLookup;
import com.extjs.gxt.ui.client.data.BeanModelReader;
import com.extjs.gxt.ui.client.data.ListLoadResult;
import com.extjs.gxt.ui.client.data.ListLoader;
import com.extjs.gxt.ui.client.data.RpcProxy;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.Info;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.form.ListField;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.rpc.AsyncCallback;
public class FeedList extends LayoutContainer {
public FeedList() {
setLayout(new FitLayout());
final FeedServiceAsync feedService = Registry
.get(RSSReaderConstants.FEED_SERVICE);
feedService.loadFeedList(new AsyncCallback<List<Feed>>() {
@Override
public void onFailure(Throwable caught) {
Info.display("RSS Reader", "Failed to loadFeedList!");
}
@Override
public void onSuccess(List<Feed> result) {
Info.display("RSS Reader", "Feed loadFeedList sucessfully size: "
+ result.size());
final ListStore<BeanModel> feedStore = Registry
.get(RSSReaderConstants.FEED_STORE);
for (Feed feed : result) {
BeanModelFactory beanModelFactory = BeanModelLookup.get()
.getFactory(feed.getClass());
feedStore.add(beanModelFactory.createModel(feed));
}
}
});
}
@Override
protected void onRender(Element parent, int index) {
super.onRender(parent, index);
final ListField<BeanModel> feedList = new ListField<BeanModel>();
final ListStore<BeanModel> feedStore = Registry
.get(RSSReaderConstants.FEED_STORE);
feedList.setStore(feedStore);
feedList.setDisplayField("title");
add(feedList);
}
}
- 注意,此时不管是add还是load操作,其影响到的feedStore始终是在Registry里面取得的。因此,feedList绑定了这个feedStore 只要feedStore有变化,feedList就会立马显示出来。