• 简单实用后台任务执行框架(Struts2+Spring+AJAX前端web界面可以获取进度)


    使用场景:

    在平常web开发过程中,有时操作员要做一个后台会运行很长时间的任务(如上传一个大文件到后台处理),而此时前台页面仍需要给用户及时的进度信息反馈,同时还要避免前台页面超时。

    框架介绍:

    本架构采用Struts+Spring+AJAX(jquery)方式实现,前台提交任务到后台,然后通过AJAX方式周期性获取任务进度,展示给用户看。

    本框架支持提交任务、查看任务进展、停止任务、删除任务。

    使用java线程池的技术来执行任务,避免不停的生成新的线程;

    代码下载(内含使用样例):

    https://github.com/jerrymousecn/daemo_tasks

    下载包说明:

    1)demo/daemonTasks.war为tomcat发布包(zip格式),可以直接放到tomcat的webapps目录;

    2)demo/demo_source目录是eclipse样例项目代码

    3)source目录是本框架源代码


    主要代码:

    1.DaemonTask.java

    后台任务基础类

    package cn.jerry.tools.tasks;
    
    import java.util.Date;
    
    public abstract class DaemonTask implements Runnable {
    	private String taskID;
    	private String taskName;
    	private String taskDesc;
    	private boolean isStartedFlag = false;;
    	private boolean isTerminated = false;;
    	private int progress;
    	private Date startTime;
    	private Date terminatedTime;
    	protected boolean toStopFlag = false;
    
    	protected abstract void execute();
    
    	protected void setProgress(int progress) {
    		this.progress = progress;
    	}
    
    	public void run() {
    		this.isStartedFlag = true;
    		this.execute();
    		this.isTerminated = true;
    		this.terminatedTime = new Date();
    	}
    
    	public String getTaskID() {
    		return taskID;
    	}
    
    	public void setTaskID(String taskID) {
    		this.taskID = taskID;
    	}
    
    	public boolean isStarted() {
    		return isStartedFlag;
    	}
    
    	public boolean getIsTerminated() {
    		return isTerminated;
    	}
    	public void setToStopFlag(boolean toStopFlag) {
    		this.toStopFlag = toStopFlag;
    	}
    
    	public Date getStartTime() {
    		return startTime;
    	}
    
    	public Date getTerminatedTime() {
    		return terminatedTime;
    	}
    
    	public int getProgress() {
    		return progress;
    	}
    
    	public String getTaskName() {
    		return taskName;
    	}
    
    	public void setTaskName(String taskName) {
    		this.taskName = taskName;
    	}
    
    	public String getTaskDesc() {
    		return taskDesc;
    	}
    
    	public void setTaskDesc(String taskDesc) {
    		this.taskDesc = taskDesc;
    	}
    
    }
    

    2.TaskManager.java

    后台任务管理类,支持添加任务,停止任务,删除任务,查看任务,对已完成任务进行定期清理,获取任务进度

    package cn.jerry.tools.tasks;
    
    import java.util.Collections;
    import java.util.Date;
    import java.util.Map;
    import java.util.Timer;
    import java.util.TimerTask;
    import java.util.UUID;
    import java.util.Map.Entry;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ConcurrentMap;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class TaskManager {
    	private static TaskManager taskManager = new TaskManager();
    	private ExecutorService executorService = Executors.newCachedThreadPool();
    	private ConcurrentMap<String, DaemonTask> taskMap = new ConcurrentHashMap<String, DaemonTask>();
    	private final int TASK_NOT_FOUND = -1;
    	private TaskCleaner taskCleaner = new TaskCleaner(taskMap);
    	private Timer timer = new Timer();
    	private final int CLEAN_PERIOD = 200000;  //in milliseconds
    
    	private String getUniqueID() {
    		return UUID.randomUUID().toString();
    	}
    
    	private TaskManager() {
    		startTerminatedTaskCleanTimer();
    	}
    
    	private void startTerminatedTaskCleanTimer() {
    		timer.schedule(taskCleaner, 0, CLEAN_PERIOD);
    	}
    
    	private void stopTerminatedTaskCleanTimer() {
    		timer.cancel();
    	}
    
    	public static TaskManager getInstance() {
    		return taskManager;
    	}
    
    	public synchronized String addTaskAndStart(DaemonTask task) {
    		String taskID = getUniqueID();
    		task.setTaskID(taskID);
    		taskMap.put(taskID, task);
    		executorService.execute(task);
    		return taskID;
    	}
    
    	public synchronized void stopTask(String taskID) {
    		DaemonTask task = getTask(taskID);
    		if (task != null) {
    			task.setToStopFlag(true);
    		}
    	}
    	public synchronized void delFinishedTask(String taskID) {
    		DaemonTask task = getTask(taskID);
    		if (task != null) {
    			if (task.getIsTerminated()) {
    				taskMap.remove(taskID);
    			}
    		}
    	}
    
    	public DaemonTask getTask(String taskID) {
    		return taskMap.get(taskID);
    	}
    	public Map<String, DaemonTask> getTasksForView() {
    		Map<String, DaemonTask> map = Collections.unmodifiableMap(taskMap);
    		return map;
    	}
    
    	public int getProgress(String taskID) {
    		int progress = TASK_NOT_FOUND;
    		DaemonTask task = getTask(taskID);
    		if (task != null) {
    			progress = task.getProgress();
    		}
    		return progress;
    	}
    
    }
    
    class TaskCleaner extends TimerTask {
    	private ConcurrentMap<String, DaemonTask> taskMap;
    
    	public TaskCleaner(ConcurrentMap<String, DaemonTask> taskMap) {
    		this.taskMap = taskMap;
    	}
    
    	@Override
    	public void run() {
    		for (Entry<String, DaemonTask> entry : taskMap.entrySet()) {
    			String taskID = entry.getKey();
    			DaemonTask task = entry.getValue();
    			if (task.getIsTerminated()) {
    				Date terminatedTime = task.getTerminatedTime();
    				Date now = new Date();
    
    				long timeOffset = getTimeOffset(terminatedTime, now);
    				if (timeOffset > 10000) {
    					taskMap.remove(taskID);
    					System.out.println("task: " + taskID + " is removed");
    				}
    			}
    		}
    	}
    
    	private long getTimeOffset(Date date1, Date date2) {
    		long time1 = date1.getTime();
    		long time2 = date2.getTime();
    		long offset = time2 - time1;
    		if (offset < 0) {
    			offset = -offset;
    		}
    		return offset;
    	}
    }
    

    3.任务样例TestTask.java

    关键点需要注意: 方法中需要自行计算进度(完成时,进度应设置为100),并且要对toStopFlag进行判断,用于终止任务。

    package cn.jerry.tools.tasks;
    
    public class TestTask extends DaemonTask {
    
    	@Override
    	protected void execute() {
    		for (int i = 0; i < 10; i++) {
    			if(this.toStopFlag==false)
    			{
    				int progress = (i + 1) * 100 / 10;
    				try {
    					Thread.sleep(1000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				this.setProgress(progress);
    			}
    		}
    	}
    }
    

    4.前台查询状态页面getTaskResult.jsp:

    <%@ taglib prefix="s" uri="/struts-tags" %>
    <html>
    <head>
    <script type="text/javascript" src="js/jquery-1.11.1.min.js"></script>
    <link rel="stylesheet" href="css/jquery-ui.css">
    <script src="js/jquery-ui.js"></script>
    <link rel="stylesheet" href="css/style.css">
    <script type="text/javascript">
    var intervalId; 
    function trim(str){
    	return str.replace(/(^s*)|(s*$)/g, ""); 
    } 
    function getprogress() {
    	htmlobj=$.ajax({url:"getTaskProgress.jsp?taskid="+'<s:property value="taskid"/>',cache:false,async:false});
    	str = trim(htmlobj.responseText);
    	$("#myDiv").html(str);
    	$( "#progressbar" ).progressbar({
    	      value: parseInt(str)
    	});
    	if(parseInt(str)>=100)
    	{
    		clearInterval(intervalId);
    	}
    }
    
    $(document).ready(function(){
    	intervalId = setInterval(getprogress, 1000);
    });
    
    </script>
    </head>
    <body>
    Task [<s:property value="taskName"/>]progress:
    	<div id="progressbar"></div>
    	<div id="myDiv"></div>
    </body>
    </html>
    

    5.相关截图

    1)进度页面截图:

    2)查看任务列表




    声明:

    本框架中使用的进度条代码实现来自以下网站,版权不属于本人,本框架仅用于学习交流。

    http://jqueryui.com/progressbar/#animated


    
    
    
  • 相关阅读:
    jquery--blur()事件,在页面加载时自动获取焦点
    jquery三级联动
    工具集
    兼容各个浏览器:禁止鼠标选择文字事件
    jquery 事件委托(利用冒泡)
    小功能1:多种方法实现网页加载进度条
    JavaSE| 泛型
    SSM整合
    Redis数据库 02事务| 持久化| 主从复制| 集群
    Hadoop| MapperReduce02 框架原理
  • 原文地址:https://www.cnblogs.com/jerry1999/p/4175932.html
Copyright © 2020-2023  润新知