【问题标题】:Storing the Cursor for App Engine Pagination为 App Engine 分页存储光标
【发布时间】:2012-10-09 21:43:03
【问题描述】:

我正在尝试使用 App Engine 的 RPC 和 GWT(它是一个应用引擎连接的项目)来实现分页。

如何将查询结果和 Web 安全游标对象从 RPC 传递给 GWT 客户端?

我见过使用 servlet 的示例,但我想知道如何在没有 servelt 的情况下做到这一点。

我考虑过使用 memcache 将光标缓存在服务器上,但我不确定这是否合适或应该使用什么作为键(我会假设会话标识符,但我不确定这些是如何处理的应用引擎)。

示例项目的链接太棒了,我一直找不到。

【问题讨论】:

    标签: google-app-engine google-cloud-datastore


    【解决方案1】:

    好的,所以最好的方法是将光标作为字符串存储在客户端上。

    为此,您必须创建一个可传输的包装类,以便您可以通过 RequestFactory 将其传递回客户端,该客户端可以保存结果列表和光标字符串。为此,您需要创建一个普通 POJO,然后为其创建一个代理。

    POJO 的代码如下所示:

    public class OrganizationResultsWrapper {
    
        public List<Organization> list;
        public String webSafeCursorString;
    
        public List<Organization> getList() {
            return list;
        }
    
        public void setList(List<Organization> list) {
            this.list = list;
        }
    
        public String getWebSafeCursorString() {
            return this.webSafeCursorString;
        }
    
        public void setWebSafeCursorString(String webSafeCursorString) {
            this.webSafeCursorString = webSafeCursorString;
        }
    }
    

    对于代理:

    @ProxyFor(OrganizationResultsWrapper.class)
    public interface OrganizationResultsWrapperProxy extends ValueProxy{
    
        List<OrganizationProxy> getList();
        void setList(List<OrganizationProxy> list);
    
        String getWebSafeCursorString();
        void setWebSafeCursorString(String webSafeCursorString);
    
    }
    

    设置你的服务和 requestFactory 分别使用 POJO 和代理

    // service class method
    @ServiceMethod
    public OrganizationResultsWrapper getOrganizations(String webSafeCursorString) {
        return dao.getOrganizations(webSafeCursorString);
    }
    
    // request factory method
    Request<OrganizationResultsWrapperProxy> getOrganizations(String webSafeCursorString); 
    

    然后确保并运行 RPC 向导,以便您的验证过程运行,否则您将在服务器上收到请求上下文错误。

    这是我的数据访问类中的实现:

    public OrganizationResultsWrapper getOrganizations(String webSafeCursorString) {
        List<Organization> list = new ArrayList<Organization>();
        OrganizationResultsWrapper resultsWrapper = new OrganizationResultsWrapper();
    
        Query<Organization> query = ofy().load().type(Organization.class).limit(50);
    
        if (webSafeCursorString != null) {
            query = query.startAt(Cursor.fromWebSafeString(webSafeCursorString));
        }
    
        QueryResultIterator<Organization> iterator = query.iterator();
        while (iterator.hasNext()) {
            list.add(iterator.next());
        }
    
        resultsWrapper.setList(list);
        resultsWrapper.setWebSafeCursorString(iterator.getCursor().toWebSafeString());
    
        return resultsWrapper;
    }
    

    【讨论】:

      【解决方案2】:

      第二个选项是将 webSafeCursorString 保存在内存缓存中,正如您已经提到的。

      我的想法是这样的:

      1. 客户端总是发送类似“getMyObjects(Object...myParams, int maxResults, String clientPaginationString)”的请求。 clientPaginationString 是唯一创建的,如下所示

      2. 服务器接收请求并查看内存缓存是否存在密钥 clientPaginationString 的 webSafeCursorString

        1. 如果服务器什么也没找到,他会创建查询并将 webSafeCursorString 保存到 memcache 中,并将 clientPaginationString 作为键。 -> 返回结果

        2. 如果服务器找到 webSafeCursorString,他会用它重新开始查询并返回结果

      问题是如何清理内存缓存以及如何找到唯一的clientPaginationString:

      唯一的 clientPaginationString 应该是当前 UserId + 当前查询的参数 + timestemp。这应该可以正常工作!

      我真的想不出一个简单的方法来清理内存缓存,但是我认为我们根本不需要清理它。 我们可以将所有 webSafeCursorStrings 和 timestemps+params+userid 存储在一个包含地图的 WebSafeCursor-Class 中,并将所有这些存储在 memcache 中......并在一段时间内清理这个 Class (时间戳更早......)。

      我能想到的一个改进是使用在服务器上创建的密钥(userSessionId + servicename + servicemethodname + params)将 webSafeCursorString 保存在内存缓存中。但是,重要的是,如果客户端对新查询感兴趣(memcache 被覆盖)或想要下一个分页结果(从 memcache 获取 webSafeCursorString),则客户端发送信息。重新加载页面应该可以工作。我认为在浏览器中再次点击会是一个问题......

      你会说什么?

      【讨论】:

        猜你喜欢
        • 2016-01-16
        • 1970-01-01
        • 2010-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-24
        相关资源
        最近更新 更多