我有一个网页,用户按下按钮并在所有应用程序(位于Tomcat中)中启动操作。
该操作是一个长时间运行的过程,我必须查看正在发生的事情的唯一方法是登录服务器并查看日志文件。
我写了一个快速的Java函数,它读取日志文件并提供有关正在发生的事情的反馈。 (基本上它只是尾随文件并解析我需要的东西)
我希望能够添加一个jsp,我可以在不登录服务器的情况下查看输出。
===
从设计的角度来看,我理解JSP应该快速返回结果而不是继续处理。
所以我的想法是创建一个简单的网页,查询jsp以获取更新并将最新信息写入屏幕。等待30秒,再次轮询服务器,并附加最新更新。
我正在努力掌握的是如何让JSP与后端进程进行通信,以及如何生成/终止该后端进程。
这是一个非常偶然的事情(每两周一次,开始完成需要一两个小时),所以我不希望守护进程一直在运行。我希望能够暂时打开它并将其关闭。
如果我从一个简单的servlet中生成一个进程,那么当我完成后如何结束该进程? 我该如何与之沟通?
答案 0 :(得分:2)
您可以创建java.lan.Runnable
女巫读取文件内容并将其保存到缓冲区中。 Runnable使用while
循环读取文件内容,以便可以从外部设置中断条件,执行Runnable的线程将在Runnable的run
方法终止时终止。
在JSP中,您可以创建java.lang.Thread
并将Runnable的实例传递给它。保存ServletContext
中可运行的实例,以便您可以跨请求访问它。如果你想终止轮询而不是从JSP设置Runnable的中断条件,那么朗姆酒方法也会终止,因此线程也会终止。
您可以使用javascript setInterval()
功能和XMLHttpRequest
刷新页面。
这是一个示例基本实现(我希望这将满足您的要求):
轮询Runnable
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"> </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;"> </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;"> </div>
</div>
</body>
</html>
修改强>
FilePollingThread
中存在一个错误:如果文件中没有可用数据,则线程可能会卡在内部while循环中。它应该是
while(line == null && polling)
JSP也无法在IE上运行(IE9上的testet)。似乎数据写入行中的响应
response.getWriter().println(pollingThread.poll());
包含孔页面的HTML。如果添加到目标div,IE似乎无法呈现它。
我使用一个简单的静态HTML文件和一个servlet创建了另一个版本,因为它提供了更多关于写入响应的内容。
如果您对代码感兴趣请告诉我。
答案 1 :(得分:1)
您应该考虑使用类似JMS的内容来控制后台流程。
对于控制,您的前端代码可以发送消息开始/停止/检查过程 对于监视,您的进程可以发布到JMS主题以供您的前端代码阅读。