- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试为我的一个 GWT 小部件合并数据缓存。
我有一个数据源接口(interface)/类,它通过 RequestBuilder
和 JSON 从我的后端检索一些数据。因为我多次显示小部件,所以我只想检索一次数据。
所以我尝试使用应用程序缓存。天真的方法是在单例对象中使用 HashMap
来存储数据。但是,如果支持,我也想使用 HTML5 的 localStorage/sessionStorage。
HTML5 localStorage 仅支持 String 值。所以我必须将我的对象转换为 JSON 并存储为字符串。但是不知何故,我想不出一个干净的方法来做到这一点。这是我目前所拥有的。
我定义了一个包含两个函数的接口(interface):fetchStatsList()
获取可以在小部件中显示的统计列表,fetchStatsData()
获取实际数据。
public interface DataSource {
public void fetchStatsData(Stat stat,FetchStatsDataCallback callback);
public void fetchStatsList(FetchStatsListCallback callback);
}
Stat
类是一个简单的 Javascript 覆盖类 (JavaScriptObject
),带有一些 getter(getName() 等)我的 DataSource 有一个正常的不可缓存实现 RequestBuilderDataSource
,如下所示:
public class RequestBuilderDataSource implements DataSource {
@Override
public void fetchStatsList(final FetchStatsListCallback callback) {
// create RequestBuilderRequest, retrieve response and parse JSON
callback.onFetchStatsList(stats);
}
@Override
public void fetchStatsData(List<Stat> stats,final FetchStatsDataCallback callback) {
String url = getStatUrl(stats);
//create RequestBuilderRquest, retrieve response and parse JSON
callback.onFetchStats(dataTable); //dataTable is of type DataTable
}
}
我省略了 RequestBuilder 的大部分代码,因为它非常简单。
这是开箱即用的,但是每次都会检索统计列表和数据,即使数据在每个小部件实例之间共享也是如此。
为了支持缓存,我添加了一个 Cache
接口(interface)和两个 Cache 实现(一个用于 HTML5 localStorage,一个用于 HashMap):
public interface Cache {
void put(Object key, Object value);
Object get(Object key);
void remove(Object key);
void clear();
}
我添加了一个新类 RequestBuilderCacheDataSource
,它扩展了 RequestBuilderDataSource
并在其构造函数中采用了一个 Cache
实例。
public class RequestBuilderCacheDataSource extends RequestBuilderDataSource {
private final Cache cache;
publlic RequestBuilderCacheDataSource(final Cache cache) {
this.cache = cache;
}
@Override
public void fetchStatsList(final FetchStatsListCallback callback) {
Object value = cache.get("list");
if (value != null) {
callback.fetchStatsList((List<Stat>)value);
}
else {
super.fetchStatsList(stats,new FetchStatsListCallback() {
@Override
public void onFetchStatsList(List<Stat>stats) {
cache.put("list",stats);
callback.onFetchStatsList(stats);
}
});
super.fetchStatsList(callback);
}
}
@Override
public void fetchStatsData(List<Stat> stats,final FetchStatsDataCallback callback) {
String url = getStatUrl(stats);
Object value = cache.get(url);
if (value != null) {
callback.onFetchStatsData((DataTable)value);
}
else {
super.fetchStatsData(stats,new FetchStatsDataCallback() {
@Override
public void onFetchStatsData(DataTable dataTable) {
cache.put(url,dataTable);
callback.onFetchStatsData(dataTable);
}
});
}
}
}
基本上新类会在Cache
中查找值,如果没有找到它会调用父类中的fetch函数并拦截回调将其放入缓存中,然后调用实际回调。
因此,为了同时支持 HTML5 本地存储和普通 JS HashMap 存储,我创建了我的 Cache
接口(interface)的两个实现:
JS HashMap存储:
public class DefaultcacheImpl implements Cache {
private HashMap<Object, Object> map;
public DefaultCacheImpl() {
this.map = new HashMap<Object, Object>();
}
@Override
public void put(Object key, Object value) {
if (key == null) {
throw new NullPointerException("key is null");
}
if (value == null) {
throw new NullPointerException("value is null");
}
map.put(key, value);
}
@Override
public Object get(Object key) {
// Check for null as Cache should not store null values / keys
if (key == null) {
throw new NullPointerException("key is null");
}
return map.get(key);
}
@Override
public void remove(Object key) {
map.remove(key);
}
@Override
public void clear() {
map.clear();
}
}
HTML5 本地存储:
public class LocalStorageImpl implements Cache{
public static enum TYPE {LOCAL,SESSION}
private TYPE type;
private Storage cacheStorage = null;
public LocalStorageImpl(TYPE type) throws Exception {
this.type = type;
if (type == TYPE.LOCAL) {
cacheStorage = Storage.getLocalStorageIfSupported();
}
else {
cacheStorage = Storage.getSessionStorageIfSupported();
}
if (cacheStorage == null) {
throw new Exception("LocalStorage not supported");
}
}
@Override
public void put(Object key, Object value) {
//Convert Object (could be any arbitrary object) into JSON
String jsonData = null;
if (value instanceof List) { // in case it is a list of Stat objects
JSONArray array = new JSONArray();
int index = 0;
for (Object val:(List)value) {
array.set(index,new JSONObject((JavaScriptObject)val));
index = index +1;
}
jsonData = array.toString();
}
else // in case it is a DataTable
{
jsonData = new JSONObject((JavaScriptObject) value).toString();
}
cacheStorage.setItem(key.toString(), jsonData);
}
@Override
public Object get(Object key) {
if (key == null) {
throw new NullPointerException("key is null");
}
String jsonDataString = cacheStorage.getItem(key.toString());
if (jsonDataString == null) {
return null;
}
Object data = null;
Object jsonData = JsonUtils.safeEval(jsonDataString);
if (!key.equals("list"))
data = DataTable.create((JavaScriptObject)data);
else if (jsonData instanceof JsArray){
JsArray<GenomeStat> jsonStats = (JsArray<GenomeStat>)jsonData;
List<GenomeStat> stats = new ArrayList<GenomeStat>();
for (int i = 0;i<jsonStats.length();i++) {
stats.add(jsonStats.get(i));
}
data = (Object)stats;
}
return data;
}
@Override
public void remove(Object key) {
cacheStorage.removeItem(key.toString());
}
@Override
public void clear() {
cacheStorage.clear();
}
public TYPE getType() {
return type;
}
}
帖子有点长,但希望能阐明我试图达到的目的。归结为两个问题:
DefaultCacheImpl
可以很容易地存储和检索任意对象。在必须转换和解析 JSON 的地方,如何使用 localStorage 实现相同的目的?我正在使用需要调用 DataTable.create(JavaScriptObject jso)
函数才能工作的 DataTable
。如果没有很多 if/else 和检查实例,我该如何解决这个问题?最佳答案
我的第一个想法:让它成为两层缓存,而不是两个不同的缓存。从内存映射开始,因此不需要序列化/反序列化来读取给定的对象,因此在一个地方更改一个对象会改变整个对象。然后依靠本地存储为下一个页面加载保留数据,避免从服务器拉取数据的需要。
我倾向于说跳过 session 存储,因为它不会持续很长时间,但它确实有它的好处。
对于存储/读取数据,我鼓励检查 AutoBeans 而不是使用 JSO。通过这种方式,您可以支持任何类型的数据(可以存储为 autobean),并且可以将 Class 参数传递给 fetcher 以指定您将从服务器/缓存读取的数据类型,并将 json 解码为 bean以同样的方式。作为一个额外的好处,autobeans 更容易定义——不需要 JSNI。一个方法可能看起来像这样(请注意,在 DataSource 及其实现中,签名是不同的)。
public <T> void fetch(Class<T> type, List<Stat> stats, Callback<T, Throwable> callback);
也就是说,DataTable.create
是什么?如果它已经是 JSO,您可以像从 RequestBuilder 数据读取时(可能)通常所做的那样转换为 DataTable。
我还鼓励不要直接从服务器返回 JSON 数组,而是将其包装在一个对象中,作为保护用户数据不被其他站点读取的最佳做法。 (好的,在重新阅读问题时,对象也不是很好)。与其在这里讨论,不如查看 JSON security best practices?
所以,综上所述,首先定义数据(不太确定这些数据是如何工作的,所以我边走边补)
public interface DataTable {
String getTableName();
void setTableName(String tableName);
}
public interface Stat {// not really clear on what this is supposed to offer
String getKey();
void setKey(String key);
String getValue();
String setValue(String value);
}
public interface TableCollection {
List<DataTable> getTables();
void setTables(List<DataTable> tables);
int getRemaining();//useful for not sending all if you have too much?
}
对于 autobeans,我们定义了一个工厂,当给定一个 Class
实例和一些数据时,它可以创建我们的任何数据。这些方法中的每一个都可以用作一种构造函数来在客户端创建一个新实例,并且可以将工厂传递给 AutoBeanCodex 以解码数据。
interface DataABF extends AutoBeanFactory {
AutoBean<DataTable> dataTable();
AutoBean<Stat> stat();
AutoBean<TableCollection> tableCollection();
}
将 String<=>Object 的所有工作委托(delegate)给 AutoBeanCodex,但您可能需要对其进行一些简单的包装,以便从 html5 缓存和 RequestBuilder 结果中轻松调用。此处的快速示例:
public class AutoBeanSerializer {
private final AutoBeanFactory factory;
public AutoBeanSerializer(AutoBeanFactory factory) {
this.factory = factory;
}
public String <T> encodeData(T data) {
//first, get the autobean mapped to the data
//probably throw something if we can't find it
AutoBean<T> autoBean = AutoBeanUtils.getAutoBean(data);
//then, encode it
//no factory or type needed here since the AutoBean has those details
return AutoBeanCodex.encode(autoBean);
}
public <T> T decodeData(Class<T> dataType, String json) {
AutoBean<T> bean = AutoBeanCodex.decode(factory, dataType, json);
//unwrap the bean, and return the actual data
return bean.as();
}
}
关于java - 使用 HTML5 localStorage 在 GWT 应用程序/小部件中缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9277593/
我想知道 GWT、GWT-RPC、EXT-GWT 和 Smart GWT 之间的区别。目前,我设法借了有关 GWT 的书籍,据我所知,它只是一个旨在促进快速高效的 Ajax(异步 JavaScript
不,这不是问如何让 Guava 在 GWT 中工作,因为我已经让它工作了。 我的问题是,当我执行继承时 我希望在命名空间 com.google.common.collect 中找到一个文件 Coll
Ext GWT 和 GWT-Ext 之间有区别吗?因为我在浏览 Ext GWT 时看到了这个页面 http://gwt-ext.com/demo/ .有什么帮助吗? 最佳答案 ExtGWT 由开发 E
调查gwt-dispatch之后和 Google Wave I/O presentation (Best practices) ( video here ),我想知道为什么官方 GWT 版本 (2.0
我在我的应用程序中使用带有 ext 的 GWT 2.0.3。该项目不再处于积极开发状态并且已被 Smart GWT 取代。我正在为此应用程序使用 HMVC 模式。现在使用现有的 GWT 2.0.3 和
当我尝试在 Windows Vista 上为 ie 8 使用 GWT 开发模式插件时,我不断看到安装插件的提示。 运行插件后我仍然总是看到这个页面。有谁知道如何解决这样的问题? 最佳答案 看这个:Ca
我正在尝试对 GWT RPC 序列化策略进行一些背景阅读,发现 GWT 在编译后将 *.gwt.rpc 文件中的可序列化类型列入白名单。 以下是我的应用程序中生成的一个此类 .gwt.rpc 文件的摘
如果 Enum 实现了 java.io.Serializable,我无法将它序列化为 GWT。它会成功编译 GWT,但在运行时,我会感到害怕: Type 'com....security..Admin
是否有可以与 GWT 一起使用的进度条小部件,还是必须自己制作?我尝试在 google-web-toolkit-incubator、gwtupload 和 upload4gwt 中使用进度条,但没有任
由于 Javadoc 没有说明使用 com.google.gwt.core.shared.GWT 的原因,它似乎包含 com.google.gwt.core.client.GWT 的功能子集,前者存在
我必须在 gwt 中创建一个图像按钮,它使用三个图像(左侧图像、中心拉伸(stretch)图像和右侧图像)。左侧图像和右侧图像具有圆角。中心图像想要拉伸(stretch)取决于按钮标题大小.创建的 I
我正在尝试在 GWT 的垂直面板中设置 align 属性,如下所示: vpanel = new VerticalPanel(); vPanel.setHorizontalAlignment(HasHo
我想在 GWT 中添加可编辑的组合框,请告诉我解决方案? 最佳答案 试试 Advanced GWT Components , 具体来说 org.gwt.advanced.client.ui.widge
我在使用 GWT Designer 配置 GXT 时遇到问题。我拥有 Eclipse、GWT 插件和 GXT 的所有新版本,但无法将 GXT 配置为与 GWT Designer 一起使用。我设置了我的
我们有一个当前使用 Capistrano 部署的应用程序。该应用程序使用 php 作为后端,使用 GWT 作为前端。 我已经设法通过 Ant 文件编译 GWT,但想用自定义 Capistrano 任务
这应该很简单,但不知何故我找不到在 GWT 中创建简单超链接的方法。基本上,我想在用户点击某些东西时加载另一个页面。 Hyperlink似乎仅指向内部 GWT 应用程序状态。我想我可以把链接放在 HT
在 GWT 界面中哪个更好,使用带有 javacode 的普通 MVP,还是 UiBinder?从性能、编辑、简单性方面。 最佳答案 这就是Google says : Besides being a
GWT 2.5.0 开发模式 我在下面对文件上传做了一个简单的测试, startupUrl: http://127.0.0.1:8888/UploadTest.html?gwt.codesvr=127
我需要创建一个SuggestBox,在按下时将显示所有选项 Enter键。 我已经写了以下实现,看来是 工作正常。 我希望有人审查我的实现情况,并让我知道 在任何特定情况下都会引起问题。 另外,要传递
在哪里可以找到有关 GWT 和 GWT-Ext 延迟加载的更多信息? 最佳答案 快速谷歌搜索显示 nice blog entry由 GWT 团队提供。 关于 GWT-Ext,我无话可说,但无论采用何种
我是一名优秀的程序员,十分优秀!