Many Web applications and enterprise applications involve long-time operations, such as complex database queries or heavy XML processing. Although these tasks are mainly completed by the database system or middleware, however, the task execution result still needs to be usedJSPCan be sent to the user. This article introduces a method to improve user perception and reduce server load by improving the front-end presentation layer.
When JSP calls an operation that must run for a long time and the result of the operation cannot be buffered (on the server side), the user must wait for a long time each time when requesting the page. Most of the time, the user will lose patience, and then try to click the refresh button of the browser, and finally leave with disappointment.
The technology introduced in this article is to separate heavy computing tasks and run them in an independent thread to solve the above problems. When a user calls a JSP page, the JSP page returns immediately and prompts that the user task has been started and is being executed. The JSP page automatically refreshes itself, report the current progress of a heavy computing task running in an independent thread until the task is completed.
I. simulate a task
First, we design a TaskBean class that implements the java. lang. Runnable interface. Its run () method runs in an independent thread started by the JSP page (start. jsp. The execution of the run () method is the responsibility of stop. JSP on another jsp page. The TaskBean class also implements the java. io. Serializable interface, so that the JSP page can call it as a JavaBean:
Packagetest. barBean;
Importjava. io. Serializable;
PublicclassTaskBeanimplementsRunnable, Serializable {
Privateintcounter;
Privateintsum;
Privatebooleanstarted;
Privatebooleanrunning;
Privateintsleep;
PublicTaskBean (){
Counter = 0;
Sum = 0;
Started = false;
Running = false;
Sleep = 100;
}
}
TaskBean's "heavy task" is computing 1 + 2 + 3... The value of + 100 is calculated by calling the work () method 100 times instead of the formula 100*(5050 + 1)/2 = 100. The code for the work () method is as follows, in which Thread. sleep () is called to ensure that the total task time is about 10 seconds.
Protectedvoidwork (){
Try {
Thread. sleep (sleep );
Counter ++;
Sum + = counter;
} Catch (InterruptedExceptione ){
SetRunning (false );
}
}
The status. jsp page obtains the task completion status by calling the following getPercent () method:
PublicsynchronizedintgetPercent (){
Returncounter;
}
If the task has been started, the isStarted () method returns true:
PublicsynchronizedbooleanisStarted (){
Returnstarted;
}
If the task has been completed, the isCompleted () method returns true:
PublicsynchronizedbooleanisCompleted (){
Returncounter = 100;
}
If the task is running, the isRunning () method returns true:
PublicsynchronizedbooleanisRunning (){
Returnrunning;
}
The SetRunning () method is called by start. jsp or stop. jsp. When the running parameter is true. The SetRunning () method also marks the task as "started ". Calling setRunning (false) indicates that the run () method is required to stop execution.
PublicsynchronizedvoidsetRunning (booleanrunning ){
This. running = running;
If (running)
Started = true;
}
After the task is completed, call the getResult () method to return the calculation result. If the task has not been completed, it returns null:
PublicsynchronizedObjectgetResult (){
If (isCompleted ())
ReturnnewInteger (sum );
Else
Returnnull;
}
When running is marked as true and completed is marked as false, the run () method calls work (). In practical applications, the run () method may need to execute complex SQL queries, parse large XML documents, or call the EJB method that consumes a lot of CPU time. Note that "heavy tasks" may be executed on remote servers. The JSP page of the report result has two options: Wait for the task to end, or use oneProgress bar.
Publicvoidrun (){
Try {
SetRunning (true );
While (isRunning ()&&! IsCompleted ())
Work ();
} Finally {
SetRunning (false );
}
}
Ii. Start the task
Start. jsp is the welcome page stated in the web. xml deployment descriptor. The content of web. xml is:
<? Xmlversion = "1.0" encoding = "GB2312"?>
<! DOCTYPEweb-app
PUBLIC "-// SunMicrosystems, Inc. // DTDWebApplication2.3 // EN"
Http://java.sun.com/dtd/web-app_2_3.dtd>
<Web-app>
<Welcome-file-list>
<Welcome-file> start. jsp </welcome-file>
</Welcome-file-list>
</Web-app>
Start. jsp start> start a dedicated thread to run "heavy tasks", and then pass the HTTP request to status. jsp.
Start. the jsp page uses the <jsp: useBean> tag to create a TaskBean instance and defines the scope attribute as a session so that other pages can be extracted to the same Bean object for HTTP requests from the same browser. Start. jsp calls the session. removeAttribute ("task") ensures that <jsp: useBean> creates a new Bean object, instead of extracting an old object (for example, the Bean object created on the JSP page earlier in the same user session ).
The following is a list of codes on the start. jsp page:
<% Session. removeAttribute ("task"); %>
<Jsp: useBeanid = "task" scope = "session"
Class = "test. barBean. TaskBean"/>
<% Task. setRunning (true); %>
<% NewThread (task). start (); %>
<Jsp: forwardpage = "status. jsp"/>
After start. jsp creates and sets the TaskBean object, it creates a Thread and passes in the Bean object as a Runnable instance. When the start () method is called, the newly created thread executes the run () method of the TaskBean object.
Now there are two threads running concurrently: the thread that executes the JSP page (called "JSP thread"), the thread created by the JSP page (called "task thread "). Next, start. jsp uses the call status. jsp and status. jsp to display the progress bar and task execution status. Note that status. jsp and start. jsp run in the same JSP thread.