实现代码
长任务
package org.infinite.ark.platform.task;
import java.util.ArrayList;
import org.infinite.ark.framework.collection.Mapx;
import org.infinite.ark.framework.util.StringFormat;
import org.infinite.ark.framework.util.StringUtil;
/**
*
* @author Darkness
* @date 2014-12-26 上午9:37:33
* @version V1.0
*/
public abstract class LongTimeTask extends Thread {
private static Mapx<Long, LongTimeTask> map = new Mapx<Long, LongTimeTask>();
private static long IDBase = System.currentTimeMillis();
private static final int MaxListSize = 1000;
private long id;
private ArrayList<String> list = new ArrayList<String>();
protected int percent;
protected String currentInfo;
private String finishedInfo;
protected ArrayList<String> errors = new ArrayList<String>();
private boolean stopFlag;
private String type;
private long stopTime = System.currentTimeMillis() + (24*60*1000L);
public static LongTimeTask createEmptyInstance() {
return new LongTimeTask(false) {
public void execute() {
}
};
}
public static LongTimeTask getInstanceById(long id) {
return map.get(id);
}
public static void removeInstanceById(long id) {
synchronized (LongTimeTask.class) {
map.remove(id);
}
}
public static String cancelByType(String type) {
String message = "该任务不存在:" + type;
LongTimeTask ltt = getInstanceByType(type);
if (ltt != null) {
ltt.stopTask();
message = "任务终止中,请稍等片刻!";
}
return message;
}
public static LongTimeTask getInstanceByType(String type) {
if (StringUtil.isNotEmpty(type)) {
long current = System.currentTimeMillis();
for (Long key : map.keyArray()) {
LongTimeTask ltt = map.get(key);
if (type.equals(ltt.getType())) {
if (current - ltt.stopTime > 60000L) {
map.remove(key);
return null;
}
return ltt;
}
}
}
return null;
}
public LongTimeTask() {
this(true);
}
private LongTimeTask(boolean flag) {
if (flag) {
setName("LongTimeTask Thread");
synchronized (LongTimeTask.class) {
this.id = (IDBase++);
map.put(this.id, this);
clearStopedTask();
}
}
}
private void clearStopedTask() {
synchronized (LongTimeTask.class) {
long current = System.currentTimeMillis();
for (Long k : map.keyArray()) {
LongTimeTask ltt = map.get(k);
if (current - ltt.stopTime > 60000L)
map.remove(k);
}
}
}
public long getTaskID() {
return this.id;
}
public void info(String message) {
this.list.add(message);
if (this.list.size() > MaxListSize)
this.list.remove(0);
}
public String[] getMessages() {
String[] arr = new String[this.list.size()];
for (int i = 0; i < arr.length; i++) {
arr[i] = ((String) this.list.get(i));
}
this.list.clear();
return arr;
}
public void run() {
if (StringUtil.isNotEmpty(this.type)) {
LongTimeTask ltt = getInstanceByType(this.type);
if ((ltt != null) && (ltt != this))
return;
}
try {
execute();
} catch (Exception ie) {
interrupt();
addError(ie.getMessage());
} finally {
this.stopTime = System.currentTimeMillis();
}
}
public abstract void execute();
public boolean checkStop() {
return this.stopFlag;
}
public void stopTask() {
clearStopedTask();
this.stopFlag = true;
}
public int getPercent() {
return this.percent;
}
public void setPercent(int percent) {
this.percent = percent;
}
public void setCurrentInfo(String currentInfo) {
this.currentInfo = currentInfo;
}
public String getCurrentInfo() {
return this.currentInfo;
}
public void setFinishedInfo(String finishedInfo) {
this.finishedInfo = finishedInfo;
}
public String getFinishedInfo() {
return this.finishedInfo;
}
public void addError(String error) {
this.errors.add(error);
}
public void addError(String[] errorArr) {
for (int i = 0; i < errorArr.length; i++)
this.errors.add(errorArr[i]);
}
public String getAllErrors() {
if (this.errors.size() == 0) {
return null;
}
StringBuilder sb = new StringBuilder();
StringFormat sf = new StringFormat("总计 ? 个错误", this.errors.size());
sb.append(sf.toString() + ":<br>");
for (int i = 0; i < this.errors.size(); i++) {
sb.append(i + 1);
sb.append(": ");
sb.append((String) this.errors.get(i));
sb.append("<br>");
}
return sb.toString();
}
public String getType() {
return this.type;
}
public void setType(String type) {
this.type = type;
}
}
长任务控制
package org.infinite.ark.platform.task;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.infinite.ark.framework.util.StringUtil;
import org.infinite.ark.platform.core.web.ajax.ActionResult;
/**
*
* @author Darkness
* @date 2014-12-26 上午9:55:56
* @version V1.0
*/
@Controller
@RequestMapping("/ark/plat/longTimeTask")
public class LongTimeTaskController {
/**
* 获取长任务信息
*
* @author Darkness
* @date 2014-12-26 上午10:17:52
* @version V1.0
*/
@ResponseBody
@RequestMapping("getInfo")
public ActionResult getInfo(Long taskId) {
if(taskId == null) {
return new ActionResult("请指定任务Id");
}
Map<String, Object> data = new HashMap<String, Object>();
LongTimeTask ltt = LongTimeTask.getInstanceById(taskId);
if ((ltt != null) && (ltt.isAlive())) {
data.put("currentInfo", StringUtil.isNotEmpty(ltt.getCurrentInfo()) ? ltt.getCurrentInfo() + "..." : "");
data.put("messages", ltt.getMessages());
data.put("percent", ltt.getPercent());
} else {
data.put("isCompleted", true);
String finishInfo = "任务己完成";
if (ltt != null) {
String errors = ltt.getAllErrors();
if (StringUtil.isNotEmpty(errors)) {
data.put("currentInfo", errors);
data.put("hasError", true);
} else {
finishInfo = StringUtil.isNotEmpty(ltt.getFinishedInfo()) ? ltt.getFinishedInfo() : finishInfo;
data.put("currentInfo", finishInfo);
}
} else {
data.put("currentInfo", finishInfo);
}
LongTimeTask.removeInstanceById(taskId);
}
return new ActionResult("任务信息", data);
}
@ResponseBody
@RequestMapping("stop")
public ActionResult stop(Long taskId) {
if(taskId == null) {
return new ActionResult("请指定任务Id");
}
LongTimeTask ltt = LongTimeTask.getInstanceById(taskId);
if (ltt != null) {
ltt.stopTask();
}
return new ActionResult("任务停止成功");
}
@ResponseBody
@RequestMapping("stopComplete")
public ActionResult stopComplete(Long taskId) {
if(taskId == null) {
return new ActionResult("请指定任务Id");
}
LongTimeTask ltt = LongTimeTask.getInstanceById(taskId);
if ((ltt == null) || (!ltt.isAlive())) {
LongTimeTask.removeInstanceById(taskId);
return new ActionResult("任务停止成功");
} else {
return new ActionResult("任务停止失败");
}
}
}
长任务示例
后端调用示例
package org.infinite.ark.platform.task;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.infinite.ark.platform.core.ServiceException;
import org.infinite.ark.platform.core.web.ajax.ActionResult;
/**
*
* @author Darkness
* @date 2014-12-26 上午10:23:44
* @version V1.0
*/
public class LongTimeTaskDemoController {
/**
* 示例方法
*
* @author Darkness
* @date 2014-12-26 上午10:08:19
* @version V1.0
*/
@ResponseBody
@RequestMapping("export")
public ActionResult exportDatabase() {
LongTimeTask ltt = LongTimeTask.getInstanceByType("exportDatabase");
if (ltt != null) {
throw new ServiceException("数据库正在导出中...");
}
ltt = new LongTimeTask() {
public void execute() {
DBExporter di = new DBExporter();
di.setTask(this);
di.importDB("export file path");
setPercent(100);
}
};
ltt.setType("exportDatabase");
ltt.start();
Map<String, Object> data = new HashMap<String, Object>();
data.put("taskId", ltt.getTaskID());
return new ActionResult("导出数据库", data);
}
}
class DBExporter {
private LongTimeTask task;
public void setTask(LongTimeTask task) {
this.task = task;
}
public void importDB(String filePath) {
String[] tables = new String[]{};
for (int i=0;i<tables.length; i++) {
this.task.setPercent(new Double(i * 100.0D /tables.length).intValue());
this.task.setCurrentInfo("Importing table " + tables[i]);
}
}
}
前端调用示例
Server.sendRequest("/Database/export.do",{},function(response){
var taskId = response.get("taskId");
var p = new Progress(taskId,"数据导出中...",500,150);
p.show();
});
/**
* 进度条示例
*/
function Progress(taskId, msg, width, height) {
this.taskId = taskId;
this.refreshTaskInfo();
}
Progress.prototype = {
refreshTaskInfo: function() {
var me = this;
var runner = new TaskRunner();
runner.start({
run: function(task) {
Server.sendRequest(
"/ark/plat/longTimeTask/getInfo.do",
{"taskId": me.taskId},
function(response, data) {
if (response.Status == 1) {
if(data.isCompleted) {// 长任务执行完毕
task.stop();// 停止前端同步任务,不再执行
if(data.hasError) {// 有错误
alert(data.currentInfo);
} else {// 没错误
alert(data.currentInfo);
}
} else {
// 设置任务不在运行中,下次才会继续定时执行
task.running = false;
me.updateProgressInfo(data.percent, data.currentInfo);
}
} else {
alert(response.Message);
}
}
);
},
interval: 500
});
},
updateProgressInfo: function(percent, progressInfo){
// 更新进度条的进度+文本
}
show: function() {
// 显示进度条
}
}
参考
一个简单的阻塞式AjaxTaskRunner实现