1

我有一个网页,用户按下按钮并在专有应用程序(驻留在 Tomcat 中)中启动操作。

该操作是一个长期运行的过程,我必须查看发生了什么的唯一方法是登录到服务器并查看日志文件。

我编写了一个快速的 Java 函数,它读取日志文件并就正在发生的事情提供反馈。(基本上它只是拖尾文件并解析出我需要的东西)

我希望能够添加一个 jsp,我可以在不登录服务器的情况下查看输出。

===

从设计的角度来看,我理解 JSP 应该快速返回结果,而不仅仅是继续处理。

所以我的想法是创建一个简单的网页,查询 jsp 的更新并将最新信息写入屏幕。等待 30 秒,再次轮询服务器,然后附加最新更新。

我正在努力掌握的是如何让 JSP 与后端进程通信,以及应该如何生成/终止该后端进程。

这是一件非常偶然的事情(每两周一次,开始完成需要一两个小时),所以我不希望守护进程一直在运行。我希望能够暂时打开它并关闭它。

如果我从一个简单的 servlet 中生成一个进程,我如何在完成后结束该进程?我如何与它沟通?

4

2 回答 2

2

您可以创建一个java.lan.Runnable女巫读取文件内容并将其保存到缓冲区中。Runnable 使用while循环读取文件内容,以便可以从外部设置中断条件,正在执行 Runnable 的线程将在 Runnable 的run方法终止时终止。

在您的 JSP 中,您可以创建一个java.lang.ThreadRunnable 实例并将其传递给它。将可运行的实例保存在 中,ServletContext以便您可以跨请求访问它。如果您想终止轮询,而不仅仅是从 JSP 设置 Runnable 的中断条件,则 rum 方法将终止,因此线程也将终止。

您可以使用 javascriptsetInterval()功能并XMLHttpRequest刷新页面。

这是一个示例基本实现(我希望这会满足您的要求):

轮询可运行

package com.web;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;

public class FilePollingThread implements Runnable {

    private String filepath = null;
    private boolean polling = false;
    private StringBuffer dataWritenAfterLastPoll = null;
    private String error = null;

    public FilePollingThread(String filepath) {
        this.filepath = filepath;
    }

    @Override
    public void run() {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(filepath)));
            dataWritenAfterLastPoll = new StringBuffer();
            polling = true;

            String line = null;

            while(polling) {
                try {
                    line = br.readLine();
                    while(line == null) {
                        try {
                            Thread.sleep(500L);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            error = e.toString();
                        }
                        line = br.readLine();
                    }
                    dataWritenAfterLastPoll.append(markUp(line));
                } catch (IOException e) {
                    e.printStackTrace();
                    error = e.toString();
                }
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            error = e.toString();
        } finally {
            if(br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    error = e.toString();
                }
            }
        }
    }

    private String markUp(String line) {
        String markup = "";
        if(line != null) {
            markup = "<div style=\"height: 6px\"><span style=\"line-height: 1.1;\">" + line + "</span></div>\n";
        }
        return markup;
    }

    public synchronized void stopPolling() {
        polling = false;
    }

    public synchronized String poll() {
        String tmp = markUp(error == null ? "Not ready" : error);
        if(dataWritenAfterLastPoll != null) {
            tmp = dataWritenAfterLastPoll.toString();
            dataWritenAfterLastPoll = new StringBuffer();
        }
        return tmp;
    }
}

一个 JSP 女巫发起轮询并不断检索数据

<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ page import="com.web.FilePollingThread" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Poll file</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<link rel="stylesheet" type="text/css" href="style/default.css"></link>
<script type="text/javascript">
    var c = 1;
    var ih;
    var polling = false;
    var filepath = null;
    function startPolling(interval) {
        ih = setInterval(function () {
            try {
                var xmlHttp = new XMLHttpRequest();
                xmlHttp.onreadystatechange = function () {
                    if(xmlHttp.readyState == 4) {
                        if(xmlHttp.status == 200) {
                            var w = getElementById('ajax_content');
                            w.innerHTML = w.innerHTML + xmlHttp.responseText;
                            getElementById('page_refresh').innerHTML = c++;
                            polling = true;
                            window.scrollTo(0, document.body.scrollHeight);
                        } else {
                            polling = false;
                            throw 'HTTP ' + xmlHttp.status;
                        }
                    }
                };
                xmlHttp.open('GET', 'pollfile.jsp?filepath=' + filepath + '&c=' + c, true);
                xmlHttp.send();
            } catch(e) {
                alert('Error at startPolling: ' + e);
                clearInterval(ih);
            }
        }, interval);
    }

    function startStopPolling() {
        var orgPolling = polling;
        try {
            if(polling) {
                polling = false;
                clearInterval(ih);
                doPolling();
            } else {
                polling = true;
                doPolling();
                startPolling(1000);
            }
            flipStartStopButtonsLabel();
        } catch(e) {
            polling = orgPolling;
            flipStartStopButtonsLabel();
            alert('Error at startStopPolling: ' + e);
        }
    }

    function flipStartStopButtonsLabel() {
        var label;
        if(polling) {
            c = 1;
            label = 'Stop polling';
            getElementById('page_refresh').innerHTML = '0';
        } else {
            label = 'Sart polling';
            getElementById('page_refresh').innerHTML = 'stoped';
        }
        var buttons = document.getElementsByName('start_stop_polling');
        if(buttons) {
            for(var i = 0; i < buttons.length; i++) {
                buttons[i].value = label;
            }
        }
    } 

    function doPolling() {
        var url = 'pollfile.jsp?polling=';
        if(polling) {
            filepath = getElementById('filepath');
            if(filepath && filepath.value && filepath.value.length > 0) {
                url += 'true&filepath=' + encodeURIComponent(filepath.value);
            } else {
                throw 'No filepath specified.';
            }
        } else {
            url += 'false';
        }
        var xmlHttp = new XMLHttpRequest();
        xmlHttp.onreadystatechange = function () {
            if(xmlHttp.readyState == 4) {
                if(xmlHttp.status != 200) {
                    throw 'HTTP ' + xmlHttp.status;
                }
            }
        };
        xmlHttp.open('POST', url, false);
        xmlHttp.send();
    }

    function clearWindow() {
        var w = getElementById('ajax_content');
        if(w) {
            w.innerHTML = '';
        }
    }

    function getElementById(id) {
        try {
            if(id) {
                elm = document.getElementById(id);
                return elm;
            } 
        } catch(e) {
            alert('Error at getElementById: ' + e);
        }
        return null;
    }
</script>
</head>
<body>


<%
    String polling = request.getParameter("polling");

    if("true".equals(polling)) {
        String filepath = request.getParameter("filepath");
        if(filepath != null && filepath.length() > 0) {
            FilePollingThread pollingThread = new FilePollingThread(filepath);
            new Thread(pollingThread, "polling thread for file '" + filepath + "'").start();
            request.getServletContext().setAttribute("pollingThread", pollingThread);
        }
    } else if("false".equals(polling)) {
        FilePollingThread pollingThread = (FilePollingThread) request.getServletContext().getAttribute("pollingThread");
        if(pollingThread != null) {
            pollingThread.stopPolling();
        }
    } else {
        FilePollingThread pollingThread = (FilePollingThread) request.getServletContext().getAttribute("pollingThread");
        if(pollingThread != null) {
            response.getWriter().println(pollingThread.poll());
            response.getWriter().close();
            return;
        }
    }
%>
<div class="label">
        <span>Page polling:</span>
    </div>
    <div style="float: left;">
        <span id="page_refresh">0</span>
    </div>
<div class="clear_both">&nbsp;</div>
<form id="input_form" action="pollfile.jsp" method="get">
    <div>
        <div style="float: left;">
            <label>Filepath:
                <input style="height: 24px;" id="filepath" type="text" size="120" value=""/>
            </label>
        </div>
        <div style="clear: both;"/>
        <div style="float: left;">
            <input style="height: 24px;" name="start_stop_polling" id="start_stop_polling_button" type="button" onclick="startStopPolling(); return false;" value="Start polling"/>
        </div>
        <div style="float: left;">
            <input style="height: 24px;" name="clear_window" id="clear_window_button" type="button" onclick="clearWindow(); return false;" value="Clear"/>
        </div>
        <div style="clear: both;">&nbsp;</div>
    </div>
</form>
<div id="ajax_content">
</div>
<div>
    <div style="float: left;">
        <input style="height: 24px;" name="start_stop_polling" id="start_stop_polling_button" type="button" onclick="startStopPolling(); return false;" value="Start polling"/>
    </div>
    <div style="float: left;">
        <input style="height: 24px;" name="clear_window" id="clear_window_button" type="button" onclick="clearWindow(); return false;" value="Clear"/>
    </div>
    <div style="clear: both;">&nbsp;</div>
</div>
</body>
</html>

编辑

有一个错误FilePollingThread:如果文件中没有可用的数据,则线程可能会卡在内部 while 循环中。它应该是

while(line == null && polling)

JSP 也不能在 IE 上工作(IE9 上的 testet)。似乎将数据写入该行中的响应

response.getWriter().println(pollingThread.poll());

包含漏洞页面的 HTML。如果添加到目标 div IE 似乎无法呈现它。

我使用一个简单的静态 HTML 文件和一个 servlet 制作了另一个版本,因为它对写入响应的内容提供了更多控制。

如果您对代码感兴趣,请告诉我。

于 2013-02-28T17:05:01.873 回答
1

您应该考虑使用JMS 之类的东西来控制您的后台进程。

为了进行控制,您的前端代码可以发送消息启动/停止/检查进程。
对于监控,您的流程可以发布到 JMS 主题以供您的前端代码阅读。

于 2013-02-28T17:11:11.620 回答