【问题标题】:Reload jsp page after computations计算后重新加载jsp页面
【发布时间】:2017-02-23 22:35:15
【问题描述】:

所以我的项目演示了使用 servlet 的 k-means 聚类算法的结果。 当我第一次集群时,一切正常,我的程序将用户重新定位到results.jsp 页面。

但是因为k-means 在选择质心时有点随机,所以我在results.jsp 的代码中添加了re-cluster 功能,它使用最初使用的设置重新聚类我的数据。

我用于重新聚类的 servlet 代码如下所示:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    do stuff...
    //reload results page
    String htmlResponse = "<html><header><meta http-equiv=\"refresh\" content=\"0; URL='results.jsp\" /></header></html>";
    writer.println(htmlResponse);
    //but this doesnt work...
}

所以集群完成后,我想重新加载resutls.jsp 页面。我尝试将JavaScript 添加到我的jsp 页面,因为refresh 是客户端操作。但是这种方法的问题是refresh 发生在集群完全完成之前。所以我在尝试打印结果时得到Exceptions。有什么建议吗?

我的refresh 脚本如下所示:

<script type="text/javascript">
        function refresh() {
            location.reload(true);
        }
</script>

<script type="text/javascript">
            function reCluster(cluster_id) {
                recluster();
            }
        </script>

.jsp 上我这样称呼:

<form class="form-horizontal" action="generateArff" method="GET" enctype="multipart/form-data">
     <button type="button" class="btn btn-default btn-lg" onclick="reCluster(); refresh();">
         <span class="glyphicon glyphicon-refresh"></span> Re-Cluster
     </button>

     <button type="submit" class="btn btn-info btn-lg">
         <span class="glyphicon glyphicon-download"></span> Generate file
     </button>
</form>

Can you advice on the matter?

【问题讨论】:

  • 抱歉,我不清楚异常来自哪里——它们是由您尝试刷新的 jsp 中的代码抛出的吗?它们是第一次被抛出还是仅在刷新后被抛出?
  • 您可以使用 AJAX 或类似方法从客户端调用服务,当工作完成后,接收回调。
  • @MarcoBolis 进行完整性检查,我设置了集群,所以最初它们有一个index of -1,所以如果在我的实施过程中发生了一些事情,我会发现错误。对于重新集群过程,我将所有现有集群重置为其原始设置。又名index -1,所以当我打印它们时,因为它们存储在ArrayList 中,你可以想象index of -1 会发生什么
  • @JoseQuintoZamora 我已经在这样做了。我正在从AJAX 调用该服务。事情是服务被调用后,客户端去refresh服务非常快,之前有足够的时间来计算new集群
  • @Jack 如果你是通过 AJAX 调用服务,那你为什么要刷新?抱歉,我正在努力更好地理解这个问题

标签: javascript java jsp servlets


【解决方案1】:

所以,@MarcoBolis 提供了一个非常好的和翔实的答案,并且肯定得到了我的 +1。

但是,我认为最简单的解决方案是最有效的解决方案。

当我看到您的代码时,我只能假设您正在对您的 servlet 使用 AJAX 请求,因为我看到 1 个 html form 带有 2 个执行不同操作的按钮。所以,我要做的是转到您的ReClusterServlet 并添加以下内容:

public class ReClusterServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter writer = response.getWriter();
        //Call your Cluster class and methods...
        //wait for it...

        //return something to your AJAX call.
        writer.print("refresh page");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }
}

现在,转到您的AJAX 请求。 我假设它将在recluster() 函数中,我看到您正在调用http 代码的head。 所以它必须是这样的:

function recluster() {
    $.ajax({
        url:'ReClusterServlet',
        type:'POST'
    });
}

这个东西,正在调用servlet,但你知道当你的servlet完成计算后它返回了success消息吗???但是你忽略它!!!

就是这一行writer.print("refresh page");

现在重写函数如下:

function recluster() {
    $.ajax({
        url:'ReClusterServlet',
        type:'POST',
        success:function() {   //handle the successful return by reloading the current page
            location.reload();
        }
    });
}

再一次,这些都是推测,因为它们似乎有点不完整,如果我错了,请随时纠正我,但我有一种强烈的感觉,你需要在client-server architectureJQuery 上多学习一点和AJAX

【讨论】:

    【解决方案2】:

    我了解到您正在向服务器发出 AJAX 调用以启动异步任务,执行集群。

    您可以通过 XHR 返回的消息通知客户端任务完成:

    function reCluster() {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'ReClusterServlet', true);
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                // Refresh if everything went OK
                if (xhr.responseText === 'Done') refresh();
            }
        };
    }
    

    棘手的部分是在 Java 端处理通知。

    如果您使用的是 Servlet API 3.x+,那么您很幸运:只需将您的请求设为异步请求即可:

    public class ReClusterServlet extends HttpServlet {
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // Defer the request to this HTTP request to later
            AsyncContext asyncCtx = request.startAsync(request, response);
            asyncCtx.setTimeout(0);
    
            // Start the long running computation in another thread,
            // passing the AsyncContext
            new MyLongRunningTask(asyncCtx).start();
        }
    }
    

    然后在另一个线程中完成:

    public class MyLongRunningTask {
        private final AsyncContext asyncCtx;
        public MyLongRunningTask(AsyncContext asyncCtx) {
            this.asyncCtx = asyncCtx;
        }
    
        // ...
    
        private void finish() {
            // Send the response asynchronously
            Writer out = this.asyncCtx.getResponse().getWriter();
            out.println("Done");
            out.flush();
    
            this.asyncContext.complete();
        }
    }
    

    如果您使用的是旧版本的 Servlet API,则必须使服务线程(调用 doGet 方法的线程)阻塞,直到计算完成。

    如果你有一个可以执行计算的线程的引用,你可以调用它的join方法来等待终止:

    public class ReClusterServlet extends HttpServlet {
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            Thread async = new MyLongRunningThread();
            async.start();
    
            // Await end of computation
            try {
                async.join();
            } catch (InterruptedException e) {
                // Computation was interrupted...
            }
    
            response.getWriter().println("Done");
        }
    }
    

    如果计算任务排队等待执行,例如通过ExecutorService,您必须使用wait/notify

    public class ReClusterServlet extends HttpServlet {
        private ExecutorService executor;
        // ...
    
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            MyLongRunningRunnable task = new MyLongRunningRunnable();
    
            synchronized (task) {
                executor.execute(task);
    
                // Put current thread to sleep until task is no more RUNNING
                // (assuming state is a property of MyLongRunningRunnable)
                while (task.getState() == State.RUNNING) {
                    try {
                        task.wait();
                    } catch (InterruptedException e) {
                        // Computation was interrupted...
                    }
                }
            }
    
            response.getWriter().println("Done");
        }
    }
    

    假设异步任务完成后调用notify

    public class MyLongRunningRunnable implements Runnable {
        private State state = State.RUNNING;
    
        // ...
    
        private synchronized void finish() {
            this.state = State.DONE;
            this.notify();
        }
    }
    

    注意如果您有 大量 传入请求并且集群作业需要很长。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-02
      相关资源
      最近更新 更多