在批量报表中实现进度条处理

报表应用中,经常会碰到一些批量报表的处理。比如批量报表生成,批量报表EXCEL导出等。

在默认情况下,在做这些报表的批处理时,在页面上只是用浏览器默认的进度条来处理。整个页面显示为空白,而用户对报表的处理进度一无所知,如果我们能在这类处理中加入类似C/S结构中的进度条处理,则会让用户感觉整个执行过程更透明,也更人性化,而且通过一定的改进和完善,可以让用户通过简单的点击操作来随时中断批处理,使得整个批流程有更好的可控性和可操作性。

设计思路:
首先我们设计一个TaskBean类,它实现java.lang.Runnable接口,其run()方法在一个由JSP页面(start.jsp)启动的独立线程中运行。终止run()方法执行由另一个JSP页面stop.jsp负责。TaskBean类还实现了java.io.Serializable接口,这样JSP页面就可以将它作为JavaBean调用。

package progress;

import java.io.Serializable;
import com.runqian.report4.model.ReportDefine;
import com.runqian.report4.usermodel.Context;
import com.runqian.report4.usermodel.Engine;
import com.runqian.report4.usermodel.IReport;
import com.runqian.report4.util.ReportUtils;

public class TaskBean implements Runnable, Serializable {
private int counter;
private int sum;
private boolean started;
private boolean running;
private int sleep;

public TaskBean() {
counter = 0;
sum = 0;
started = false;
running = false;
sleep = 50;
}

/**
* TaskBean包含的”批任务”是使用API计算100张报表。 调用work()方法100次完成计算。work()方法的代码如下所示,
* 其中调用Thread.sleep()是为了确保每次使用API计算报表任务都有一定的间隔,在页面上能更明确的看到进度条的进度情况。在实际应用中因为报表数据量和导出等耗费时间的计算,就不需要这个SLEEP方法了。
*/
protected void work() {
try {
Thread.sleep(sleep);
// 计算报表
String reportFile = “c:\\test1.raq”;
Context cxt = new Context();
ReportDefine rd;
try {
rd = (ReportDefine) ReportUtils.read(reportFile);

Engine engine = new Engine(rd, cxt); // 构造报表引擎
IReport iReport = engine.calc(); // 运算报表
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();

counter = counter + 1;
sum += 1;
} catch (Exception e) {
setRunning(false);

}

// status.jsp页面通过调用下面的getPercent()方法获得任务的完成状况:
public synchronized int getPercent() {
return counter;
}

// 如果任务已经启动,isStarted()方法将返回true:
public synchronized boolean isStarted() {
return started;
}

// 如果任务已经完成,isCompleted()方法将返回true
public synchronized boolean isCompleted() {
return counter == 100;
}

// 如果任务正在运行,isRunning()方法将返回true:
public synchronized boolean isRunning() {
return running;
}

/**
* SetRunning()方法由start.jsp或stop.jsp调用,
* 当running参数是true时。SetRunning()方法还要将任务标记为”已经启动”。
* 调用setRunning(false)表示要求run()方法停止执行。
*/
public synchronized void setRunning(boolean running) {
this.running = running;
if (running) {
started = true;

}

// 任务执行完毕后,调用getResult()方法返回计算结果;如果任务尚未执行完毕,它返回null:
public synchronized Object getResult() {
if (isCompleted()) {
return new Integer(sum);
} else {
return null;

}

/**
* 当running标记为true、completed标记为false时, run()方法调用work()。在实际应用中,run()方法也许要
* 执行批量报表生成、批量报表导出,或者调用消耗大量 CPU时间的API方法。
*/
public void run() {
boolean flag = false;
try {
setRunning(true);
System.out.println(“start”);
while (isRunning() && !isCompleted()) {
work();

} catch (Exception e) {
} finally {
setRunning(false);



然后我们需要三个JSP页面:启动整个批处理的页面start.jsp,显示整个处理过程进度条并可在执行过程中终止批处理操作的页面status.jsp,终止批处理执行的页面stop.jsp.

首先是start.jsp:

<%@ page contentType=”text/html; charset=GBK” %>
<% session.removeAttribute(“task”); %>
<jsp:useBean id=”task” scope=”session” class=”progress.TaskBean”/>
<% task.setRunning(true); %>
<% new Thread(task).start(); %>
<jsp:forward page=”status.jsp”/>

红色的部分,第一步是实例化TaskBean,第二步是调用TaskBean中的setRunning()方法,设置整个批处理流程的初始状态,第三部是调用TaskBean中的start()方法,开始整个批处理的执行,然后显示状态页面。

然后是stop.jsp:

<%@ page contentType=”text/html; charset=GBK” %>
<jsp:useBean id=”task” scope=”session” class=”progress.TaskBean”/>
<% task.setRunning(false); %>
<jsp:forward page=”status.jsp”/>

和start.jsp类似,在红色部分中,第二步是调用TaskBean中的setRunning()方法,设置批处理的状态为false,这样在下一次做判断时,根据该状态,终止整个线程的运行。然后显示状态页面。

最后是状态页面status.jsp:

<%@ page contentType=”text/html; charset=GBK” %>
<jsp:useBean id=”task” scope=”session” class=”progress.TaskBean”/>
<HTML>
<HEAD>
<TITLE>报表生成进度</TITLE>
<% if (task.isRunning()) { %>
<script type=”" LANGUAGE=”JavaScript”>
setTimeout(“location=’status.jsp’”, 1000);
</script>
<% } %>
</HEAD>
<BODY bgcolor=”">

<H1 ALIGN=”CENTER”>报表生成进度</H1>
<H2 ALIGN=”CENTER”>
结果: <%= task.getResult() %><BR>
<% int percent = task.getPercent(); %>
<%= percent %>%
</H2>
<TABLE WIDTH=”60%” ALIGN=”CENTER”
CELLPADDING=0 CELLSPACING=2>
<TR>
<% for (int i = 1; i <= percent; i += 1) { %>
<TD WIDTH=”1%” height=”10″ BGCOLOR=”green”> </TD>
<% } %>
<% for (int i = 100; i > percent; i -= 1) { %>
<TD WIDTH=”1%” height=”10″ BGCOLOR=”red”> </TD>
<% } %>
</TR>
</TABLE>
<TABLE WIDTH=”100%” BORDER=0 CELLPADDING=0 CELLSPACING=0>
<TR>
<TD ALIGN=”CENTER”>
<% if (task.isRunning()) { %>
正在执行
<% } else { %>
<% if (task.isCompleted()) { %>
完成
<% } else if (!task.isStarted()) { %>
尚未开始
<% } else { %>
已停止
<% } %>
<% } %>
</TD>
</TR>
<TR>
<TD ALIGN=”CENTER”>
<BR>
<% if (task.isRunning()) { %>
<FORM METHOD=”GET” ACTION=”stop.jsp”>
<INPUT TYPE=”SUBMIT” name=”停止” value=”停止”>
</FORM>
<% } else { %>
<FORM METHOD=”GET” ACTION=”start.jsp”>
<INPUT TYPE=”SUBMIT” name=”开始” value=”开始”>
</FORM>
<% } %>
</TD>
</TR>
</TABLE>
</BODY></HTML>

在这个页面中,我们主要做的事情就是根据TaskBean中的方法,在页面上获得处理结果并将其以进度条和状态标识显示出来。

JAVABEAN和三个页面完成后,我们就可以从START.jsp页面进入,然后点击开始按钮,看到进度条和后台批处理的执行效果了,同时可以点击停止按钮随时终止批处理的执行过程