长任务实现

实现代码

长任务

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实现


你可能感兴趣的:(长任务实现)