精华内容
下载资源
问答
  • 动态quartz定时任务实现,是把定时任务数据库,不是.xml

    大家好,小学生又来为初级者分享一下技术了。这节我们来分享quartz动态定时任务的实现,因为楼主公司项目的需要,所以前端时间自己了解了一下动态更改的quartz定时任务功能。我刚开始也是看了需要帖子,发现大多数定时任务还是写在.xml配置里面的,这样写的最大缺点就是如果因为公司需要把定时任务执行的时间、或者是执行类更换,就需要修改.xml代码并重新提交发布版本才行。为此出了一种写到数据库里的动态定时任务技术。如下......

    我在上节讲了maven创建ssm框架的多模块项目,此次也是根据上次的代码进行编写分享的,如有需要可以点击查看上篇博客 maven多模块

    1、我们需要在父项目的pom.xml文件中加入jar依赖:

    <dependency><span style="white-space:pre">	
    <span style="white-space:pre">	</span><groupId>org.quartz-scheduler</groupId>
    	<artifactId>quartz</artifactId>
    	<version>1.8.6</version>
    </dependency>
    <dependency>
    	<groupId>org.slf4j</groupId>
    	<artifactId>slf4j-log4j12</artifactId>
    	<version>1.7.2</version>
    </dependency>

    
    

    2、为了项目开发方便的需要,我们需要创建两个工具实体类:

    (1)定时任务工具类QuartzManager(主要是对quartz的新增、更改、关闭等)

    package com.xzhang.util;
    
    import java.util.Date;
    
    import org.quartz.CronTrigger;
    import org.quartz.JobDetail;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerException;
    import org.quartz.SchedulerFactory;
    import org.quartz.Trigger;
    import org.quartz.impl.StdSchedulerFactory;
    
    /**  
    * @Title: QuartzManager.java
    * @Package com.xzhang.util
    * @Description: TODO(定时任务管理类)
    * @author zx  
    * @date 2016-8-22 下午3:28:57
    */ 
    public class QuartzManager {
    	
    	private static SchedulerFactory gSchedulerFactory = new StdSchedulerFactory();  
        private static String JOB_GROUP_NAME = "EXTJWEB_JOBGROUP_NAME";  
        private static String TRIGGER_GROUP_NAME = "EXTJWEB_TRIGGERGROUP_NAME";  
      
        /** 
         * @Description: 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名 
         *  
         * @param jobName 
         *            任务名 
         * @param cls 
         *            任务 
         * @param time 
         *            时间设置,参考quartz说明文档 
         *  
         * @Title: QuartzManager.java 
         * @Copyright: Copyright (c) 2014 
         *  
         * @author Comsys-LZP 
         * @date 2014-6-26 下午03:47:44 
         * @version V2.0 
         */  
        @SuppressWarnings("unchecked")  
        public static void addJob(String jobName, Class cls, String time) {  
            try {  
                Scheduler sched = gSchedulerFactory.getScheduler();  
                JobDetail jobDetail = new JobDetail(jobName, JOB_GROUP_NAME, cls);// 任务名,任务组,任务执行类  
                // 触发器  
                CronTrigger trigger = new CronTrigger(jobName, TRIGGER_GROUP_NAME);// 触发器名,触发器组  
                trigger.setCronExpression(time);// 触发器时间设定  
                sched.scheduleJob(jobDetail, trigger);  
                // 启动  
                if (!sched.isShutdown()) {  
                    sched.start();  
                }  
            } catch (Exception e) {  
                throw new RuntimeException(e);  
            }  
        }  
      
        /** 
         * @Description: 添加一个定时任务 
         *  
         * @param jobName 
         *            任务名 
         * @param jobGroupName 
         *            任务组名 
         * @param triggerName 
         *            触发器名 
         * @param triggerGroupName 
         *            触发器组名 
         * @param jobClass 
         *            任务 
         * @param time 
         *            时间设置,参考quartz说明文档 
         *  
         * @Title: QuartzManager.java 
         * @Copyright: Copyright (c) 2014 
         *  
         * @author Comsys-LZP 
         * @date 2014-6-26 下午03:48:15 
         * @version V2.0 
         */  
        @SuppressWarnings("unchecked")  
        public static void addJob(String jobName, String jobGroupName,  
                String triggerName, String triggerGroupName, Class jobClass,  
                String time) {  
            try {  
                Scheduler sched = gSchedulerFactory.getScheduler();  
                JobDetail jobDetail = new JobDetail(jobName, jobGroupName, jobClass);// 任务名,任务组,任务执行类  
                // 触发器  
                CronTrigger trigger = new CronTrigger(triggerName, triggerGroupName);// 触发器名,触发器组  
                trigger.setCronExpression(time);// 触发器时间设定  
                sched.scheduleJob(jobDetail, trigger);
                // 启动  
                if (!sched.isShutdown()) {  
                    sched.start();  
                } 
            } catch (Exception e) {  
                throw new RuntimeException(e);  
            }  
        }  
      
        /** 
         * @Description: 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名) 
         *  
         * @param jobName 
         * @param time 
         *  
         * @Title: QuartzManager.java 
         * @Copyright: Copyright (c) 2014 
         *  
         * @author Comsys-LZP 
         * @date 2014-6-26 下午03:49:21 
         * @version V2.0 
         */  
        @SuppressWarnings("unchecked")  
        public static void modifyJobTime(String jobName, String time) {  
            try {  
                Scheduler sched = gSchedulerFactory.getScheduler();  
                CronTrigger trigger = (CronTrigger) sched.getTrigger(jobName,TRIGGER_GROUP_NAME);  
                if (trigger == null) {  
                    return;  
                }  
                String oldTime = trigger.getCronExpression();  
                if (!oldTime.equalsIgnoreCase(time)) {  
                    JobDetail jobDetail = sched.getJobDetail(jobName,JOB_GROUP_NAME);  
                    Class objJobClass = jobDetail.getJobClass();  
                    removeJob(jobName);  
                    addJob(jobName, objJobClass, time);  
                }  
            } catch (Exception e) {  
                throw new RuntimeException(e);  
            }  
        }  
      
        /** 
         * @Description: 修改一个任务的触发时间 
         *  
         * @param triggerName 
         * @param triggerGroupName 
         * @param time 
         *  
         * @Title: QuartzManager.java 
         * @Copyright: Copyright (c) 2014 
         *  
         * @author Comsys-LZP 
         * @date 2014-6-26 下午03:49:37 
         * @version V2.0 
         */  
        public static void modifyJobTime(String triggerName,  
                String triggerGroupName, String time) {  
            try {  
                Scheduler sched = gSchedulerFactory.getScheduler();  
                CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerName,triggerGroupName);  
                if (trigger == null) {  
                    return;  
                }  
                String oldTime = trigger.getCronExpression();  
                if (!oldTime.equalsIgnoreCase(time)) {  
                    CronTrigger ct = (CronTrigger) trigger;  
                    // 修改时间  
                    ct.setCronExpression(time);  
                    // 重启触发器  
                    sched.resumeTrigger(triggerName, triggerGroupName);  
                }  
            } catch (Exception e) {  
                throw new RuntimeException(e);  
            }  
        }  
        
        /**
         * 更新任务时间:先移除、再新增
         * @param triggerName
         * @param triggerGroupName
         * @param time
         */
        public static void modifyJobTimeTrue(String jobName, String jobGroupName,  
                String triggerName, String triggerGroupName, Class jobClass,  
                String time){
        	//先移除
        	removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
        	//再新增
        	addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, time);
        }
      
        /** 
         * @Description: 移除一个任务(使用默认的任务组名,触发器名,触发器组名) 
         *  
         * @param jobName 
         *  
         * @Title: QuartzManager.java 
         * @Copyright: Copyright (c) 2014 
         *  
         * @author Comsys-LZP 
         * @date 2014-6-26 下午03:49:51 
         * @version V2.0 
         */  
        public static void removeJob(String jobName) {  
            try {  
                Scheduler sched = gSchedulerFactory.getScheduler();  
                sched.pauseTrigger(jobName, TRIGGER_GROUP_NAME);// 停止触发器  
                sched.unscheduleJob(jobName, TRIGGER_GROUP_NAME);// 移除触发器  
                sched.deleteJob(jobName, JOB_GROUP_NAME);// 删除任务  
            } catch (Exception e) {  
                throw new RuntimeException(e);  
            }  
        }  
      
        /** 
         * @Description: 移除一个任务 
         *  
         * @param jobName 
         * @param jobGroupName 
         * @param triggerName 
         * @param triggerGroupName 
         *  
         * @Title: QuartzManager.java 
         * @Copyright: Copyright (c) 2014 
         *  
         * @author Comsys-LZP 
         * @date 2014-6-26 下午03:50:01 
         * @version V2.0 
         */  
        public static void removeJob(String jobName, String jobGroupName,  
                String triggerName, String triggerGroupName) {  
            try {  
                Scheduler sched = gSchedulerFactory.getScheduler();  
                sched.pauseTrigger(triggerName, triggerGroupName);// 停止触发器  
                sched.unscheduleJob(triggerName, triggerGroupName);// 移除触发器  
                sched.deleteJob(jobName, jobGroupName);// 删除任务  
            } catch (Exception e) {  
                throw new RuntimeException(e);  
            }  
        }  
      
        /** 
         * @Description:启动所有定时任务 
         *  
         *  
         * @Title: QuartzManager.java 
         * @Copyright: Copyright (c) 2014 
         *  
         * @author Comsys-LZP 
         * @date 2014-6-26 下午03:50:18 
         * @version V2.0 
         */  
        public static void startJobs() {  
            try {  
                Scheduler sched = gSchedulerFactory.getScheduler();  
                sched.start();  
            } catch (Exception e) {  
                throw new RuntimeException(e);  
            }  
        }  
      
        /** 
         * @Description:关闭所有定时任务 
         *  
         *  
         * @Title: QuartzManager.java 
         * @Copyright: Copyright (c) 2014 
         *  
         * @author Comsys-LZP 
         * @date 2014-6-26 下午03:50:26 
         * @version V2.0 
         */  
        public static void shutdownJobs() {  
            try {  
                Scheduler sched = gSchedulerFactory.getScheduler();  
                if (!sched.isShutdown()) {  
                    sched.shutdown();  
                }  
            } catch (Exception e) {  
                throw new RuntimeException(e);  
            }  
        }
        
        /** 
         * 停止一个job任务 
         * @param jobkey 
         * @throws SchedulerException 
         */  
        public static void pauseJob(String jobName, String groupName,String triggerName) throws SchedulerException  { 
        	Scheduler sched = gSchedulerFactory.getScheduler();
        	//sched.pauseTrigger(triggerName, groupName);
        	//sched.pauseJob(jobName, groupName);
        	sched.interrupt(jobName, groupName);
        }
        
        /** 
         * 恢复相关的job任务 
         * @param jobkey 
         * @throws SchedulerException 
         */  
        public static void resumeJob(String jobName, String groupName,String triggerName) throws SchedulerException {  
        	Scheduler sched = gSchedulerFactory.getScheduler();
        	//sched.resumeTrigger(triggerName, groupName);
        	sched.resumeJob(jobName, groupName);  
        }
    
    }
    
    (2)SpringContextUtil(spring相关的工具类,主要为了获取到项目中定义的service bean)

    /**
     * 
     */
    package com.xzhang.web;
    
    import java.util.Locale;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.web.servlet.i18n.SessionLocaleResolver;
    
    /**
     * Spring相关工具类
     * 
     * @author Jian
     * @date 2012-8-15
     */
    public class SpringContextUtil implements ApplicationContextAware {
    	private static ApplicationContext applicationContext;
    
    	/**
    	 * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
    	 */
    	public void setApplicationContext(ApplicationContext applicationContext) {
    		SpringContextUtil.applicationContext = applicationContext;
    	}
    
    	/**
    	 * 取得存储在静态变量中的ApplicationContext.
    	 */
    	public static ApplicationContext getApplicationContext() {
    		checkApplicationContext();
    		return applicationContext;
    	}
    
    	/**
    	 * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
    	 */
    	@SuppressWarnings("unchecked")
    	public static <T> T getBean(String name) {
    		checkApplicationContext();
    		return (T) applicationContext.getBean(name);
    	}
    
    	/**
    	 * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
    	 */
    	@SuppressWarnings("unchecked")
    	public static <T> T getBean(Class<T> clazz) {
    		checkApplicationContext();
    		return (T) applicationContext.getBeansOfType(clazz);
    	}
    
    	private static void checkApplicationContext() {
    		if (applicationContext == null)
    			throw new IllegalStateException("applicaitonContext未注入,请在spring-mvc.xml中定义SpringContextUtil");
    	}
    
    	public static String getMessage(String key, HttpServletRequest request) {
    		return applicationContext.getMessage(key, null, getLocal(request));
    	}
    
    	public static String getMessage(String key, String[] args, HttpServletRequest request) {
    		return applicationContext.getMessage(key, args, getLocal(request));
    	}
    
    	public static Locale getLocal(HttpServletRequest request) {
    		Locale locale = (Locale) request.getSession().getAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME);
    		if (locale == null) {
    			locale = request.getLocale();
    		}
    
    		return locale;
    	}
    }
    


    3、创建一张定时任务详细表(即用来存储的所有的定时任务信息),楼主这里用的是MySQL

    -- 定时任务表
    CREATE TABLE t_instmt_quartz
    (
    	id VARCHAR(100) PRIMARY KEY ,
    	job_group VARCHAR(256) COMMENT '任务组',
    	trigger_group VARCHAR(256) COMMENT '触发器组',  
    	job_name VARCHAR(128) COMMENT '任务名', 
    	trigger_name VARCHAR(128) COMMENT '触发器名',   
    	class_name VARCHAR(128) COMMENT '执行代码的类名', 
    	enable_status VARCHAR(2) DEFAULT '1' COMMENT '是否禁用:0禁用;1启用',
    	trigger_cron VARCHAR(128) COMMENT '触发器类型(时间) */5 * * * * ?',
    	trigger_status VARCHAR(2) COMMENT '任务状态:0关闭;1运行中;2暂停;',
    	crate_time DATETIME COMMENT '创建时间',
    	update_time DATETIME COMMENT '更新时间',
    	desc_ript VARCHAR(1024) COMMENT '描述'
    );

    手动输入一条数据如下图



    4、然后根据表创建实体类:QuartzManager;创建相关的dao层、service层

    5、创建一个总的定时任务启动类:InstantiationTracingBeanPostProcessor,用来在spring加载完成就进行启动检索所有的定时任务并启动。

    package com.xzhang.controller;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.annotation.PostConstruct;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.event.ContextRefreshedEvent;
    
    import com.alibaba.fastjson.JSON;
    import com.xzhang.model.InstmtQuartz;
    import com.xzhang.service.IQuartzService;
    import com.xzhang.util.QuartzManager;
    
    /**  
    * @Title: InstantiationTracingBeanPostProcessor.java
    * @Package com.xzhang.controller
    * @Description: TODO(所有定时任务的启动类:当spring启动的时候它就跟着启动)
    * @author zx  
    * @date 2016-8-22 下午4:28:24
    */ 
    public class InstantiationTracingBeanPostProcessor  {
    
    	private IQuartzService quartzService;
    	public IQuartzService getQuartzService() {
    		return quartzService;
    	}
    	public void setQuartzService(IQuartzService quartzService) {
    		this.quartzService = quartzService;
    	}
    	
    
    	/* spring加载完就执行该方法:init-method="autoLoadTask" */
    	public void autoLoadTask() {
    		//获取到所有需要启动的quartz集合
    		System.out.println("【系统启动】所有定时任务开启...");
    		Map<String, Object> conditions = new HashMap<String, Object>();
    		conditions.put("enablestatus", InstmtQuartz.ENABLE_STATUS_YES);
    		conditions.put("triggerstatus", "");
    		List<InstmtQuartz> quartzList = quartzService.getInstmtQuartzList(conditions);
    		if(null == quartzList)return;
    		for(int i=0;i<quartzList.size();i++){
    			System.out.println("定时任务个数:"+quartzList.size());
    			try {
    				QuartzManager.addJob(quartzList.get(i).getJobname(), quartzList.get(i).getJobgroup(), 
    						quartzList.get(i).getTriggername(), quartzList.get(i).getTriggergroup(), 
    						Class.forName(quartzList.get(i).getClassname()), quartzList.get(i).getTriggercron());
    			} catch (ClassNotFoundException e) {
    				e.printStackTrace();
    			}
    		}
    		
    	}
    
    }
    


    6、同时我们需要在spring-mvc.xml文件中添加如下配置:

    <!-- 定义SpringContextUtil工具类 -->
    <bean id="springContextUtil" class="com.xzhang.web.SpringContextUtil" />
    <!-- 定时任务:要求所有的定时任务在spring启动之后跟着启动 -->
    <bean id="instantiationTracingBeanPostProcessor" init-method="autoLoadTask" class="com.xzhang.controller.InstantiationTracingBeanPostProcessor" >
    	<property name="quartzService" ref="quartzService" />
    </bean>

    如上代码所示:(1)第一个配置是为了定义声明SpringContextUtil,因为利用了这个工具类去获取了项目中注解的service;

    (2)第二个配置是为了在spring启动完成后就执行InstantiationTracingBeanPostProcessor类中的方法autoLoadTask,并注入了quartzService


    7、编写一个测试的定时任务执行类,如下:

    package com.xzhang.controller;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.List;
    
    import org.apache.log4j.Logger;
    import org.quartz.InterruptableJob;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.quartz.UnableToInterruptJobException;
    
    import com.xzhang.model.User;
    import com.xzhang.service.IUserService;
    import com.xzhang.web.SpringContextUtil;
    
    /**
     * 定时任务--打印测试定时任务是否成功
     * @author zx
     *
     */
    public class TestQuartzTask implements InterruptableJob {
    	protected Logger log = Logger.getLogger(this.getClass());
    	private boolean _interrupted = false;
    	
    	/*此处引入相关的service*/
    	private IUserService userService = SpringContextUtil.getBean("userService");
    	
    
    	@Override
    	public void execute(JobExecutionContext arg0) throws JobExecutionException {
    		if(null == userService){
    			System.out.println("userService为null");
    		}
    		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    		System.out.println(sf.format(new Date())+
    				"定时任务TestQuartzTask.class启动!!!");
    		/*
    		 * 获取所有的用户列表,并循环打印
    		 * */
    		List<User> users = userService.getAll();
    		if(null != users && users.size()>0){
    			for(User u : users){
    				//判断是否点击了‘立刻停止’
    				if(_interrupted) {  
    	                 System.out.println("定时任务ExpectedBillSmsTask.class立刻停止!!!");
    	                 return; 
    	            }
    				
    				System.out.println(sf.format(new Date())+":"+u.getName());
    			}
    		}
    	}
    
    	@Override
    	public void interrupt() throws UnableToInterruptJobException {
    		System.out.println("【关闭】interrupt执行立刻停止:test定时发送...");
    		log.info("【关闭】interrupt执行立刻停止:test定时发送...");
    		_interrupted = true;
    	}
    
    }
    
    注:这个执行类实现了InterruptableJob类,之所以实现这个类主要是想利用InterruptableJob类中private boolean _interrupted = false;这个作用是当在定时任务管理界面点击【立即停止】时,会让_interrupted =true,会中止for循环,也就停止了定时任务的执行了。


    好了,就到这里吧,如果大家有疑问可以随时联系楼主这个小学生,楼主的代码里也许会有不合理的地方,欢迎大家指出、相互交流。

    楼主QQ:752058871










    展开全文
  • 项目一 需求,纯后台项目,开发一个自动功能每日定时获取数据库里前一天某些数据,发送到外部系统交互,得到返回结果之后将结果记录回数据库。 项目选用框架 Spring集成quarz来完成定时任务一直是我第一选择。...

     11月接了两个小项目的开发任务,时间有点紧,代码还有很多可以优化的地方

    项目一

    需求,纯后台项目,开发一个自动功能每日定时获取数据库里前一天某些数据,发送到外部系统交互,得到返回结果之后将结果记录回数据库。

    项目选用框架

    Spring集成quarz来完成定时任务一直是我第一选择。数据库框架,选用了mybatis进行集成,虽然我一直偏爱jdbcTemplate和JPA。

     

    技术处理重点:多线程处理和线程池配合

    具体业务平均每一小时有大概两万多条的数据需要进行发送到外部系统进行交互,交互完毕之后,更新数据。但是,因为每条数据里都有大字段,造成了每次查询和更新都比较慢,单线程的话,操作下来大概时间在两个小时左右。故想换成多线程。

     

    处理的数据流程详细为这么一个流程:1从数据库中扫描出数据2将数据发送到外部系统处理3将处理的结果更新到数据库。

    性能卡在第2步,因为使用外网交互,网络交互消耗了很多时间。

    现在的想法是,因为发送外部系统耗时比较久,更新数据库耗时时间比较短,

    故,想将这两个步骤分开,使用两个线程池进行分别操作,

    考虑了两种方法进行操作,将123作为一个整体任务,由一个有多条分发线程的线程池进行任务的分发,每一个整体任务作为一条工作线程进行真正的工作。这种做法比较简单,也比较容易完成。但是我考虑的是,如果因为第2步耗时的原因,会导致整个流程停滞,这个不是我想要的。

    于是我考虑的是第二种做法,将1作为一个整体,作为一个任务,将23作为一个单独的任务,进行单独操作。(1任务为生产者放入线程池1,23为消费者放入线程池2)

     

    如果基于这种做法,那么接下来的需要考虑的就是如何存放生产者得到的数据,最开始考虑的是ConcurrentHashMap,但是,存在着没有办法在两个线程池中传递key的问题,很可能第二个线程池运行的时候,第一个线程池还没有把数据放入currentMap中。

    最后选用的是采用缓存的形式,选用了ConcurrentLinkedQueue 来offer进数据,而生产者到这个Queue来进行poll。但是这样又会有一个问题了,如何判断队列中的任务是否被执行完。为什么会有这个问题呢,

    线程池1每60分钟从数据库里面获取数据,然互offer进队列

    线程池2每10分钟从队列中poll出数据来,外部系统交互,更改数据库数据的标记位。

    现在的问题是,2执行效率很慢,10*6次没有办法将队列中的任务全部执行完,也就是其实任务是压到了线程池的阻塞队列中,而没有执行(没有更改标记位),而1的定时时间又到了,造成了重复获取了数据库的数据。所以我想判断2中的阻塞队列中的任务是否被执行完,如果执行完了,就让1去获取数据,如果没有执行完,就不让1去获取重复的数据。

    但是,要判断队列中的任务是否被完全执行是不可能的。。比如,用队列的长度去判断。用队列的长度作为判断是不准确的,因为有可能我的数据已经被扫到任务里了,但是工作线程没启动,所以,还没被压进队列。如下代码:

     ArrayList<SignatureData>customers= (ArrayList<SignatureData>) signedDataMapper.getSignatureDataToTSP(hashMap);

           int count = customers.size();

           for(int i=0;i<count;i++){

             TSPPOOL.execute(newTSPThread(customers.get(i),countDownLatch));

           }


    其中signedDataMapper.getSignatureDataToTSP(hashMap);这一步,将数据库中的所有需要扫描的数据进行了扫描,但是还没有offer进队列,如果这个时候消费者线程池去判断队列的长度为0,就会认为是没有任务需要执行,这是不对的。

    那么接下来 问题就很明确了,我需要线程池1完成操作之后,线程池2才能进行操作。这时候,我使用了一个很好用的工具CountDownLatch。通过它的计数。就可以完成这个工作。为了保险,我还在缓存中加入了一个变量,启动生产者线程池的定时器线程判断这个值是否为0,如果不为0,是因为上一次的认为还没被消费完,就不执生产了。为0的话,执行生产,将生产的总数设置进去。启动消费者线程池的定时器线程去判断这个数是否为0,为0则不去执行,不为0则执行取到的这个值,执行完之后,消费者线程池通过CountDownLatch这个工具判读执行完这个值的次数之后,再将这个值设置为0。到这里,两个线程池的配合就准确无误了。

    最终代码

    生产者:

    if((CacheUtil.INSTANCE.getCountTasks()!=0)){
        System.out.println("还有未处理完的数据,延迟扫描数据");
        return;
        }

           ArrayList<SignatureData>customers = (ArrayList<SignatureData>) signedDataMapper.getSignatureDataToTSP(hashMap);
           int count = customers.size();
           CountDownLatch countDownLatch = new CountDownLatch(count);
           for(int i=0;i<count;i++){
             TSPPOOL.execute(new TSPThread(customers.get(i),countDownLatch));
           }
           countDownLatch.await();
           CacheUtil.INSTANCE.setCountTasks(count);

    消费者

    if(CacheUtil.INSTANCE.getCountTasks()==0){

    return;
    }
    System.out.println("更新数据前有数据"+CacheUtil.INSTANCE.getDatas().size()+"条");
    CountDownLatch countDownLatch = new CountDownLatch(CacheUtil.INSTANCE.getCountTasks());
    while(!CacheUtil.INSTANCE.getDatas().isEmpty()){
    updatePool.execute(new UpdateThread(CacheUtil.INSTANCE.getDatas().poll(),countDownLatch));
    }
    System.out.println("更新数据后有数据"+CacheUtil.INSTANCE.getDatas().size()+"条");
    countDownLatch.await();
    CacheUtil.INSTANCE.setCountTasks(0);

    附:mybatis对blob的处理相当简单,实体类用byte[]去接收,mapper.xml文件中配置为:#{xx,jdbcType=BLOB}。



    展开全文
  • 软件外包项目中,甲方(发包商)通过资金或其它资源获取乙方(承包商)的开发服务,以达成其软件需求目标。为了让外包项目按时按质按量完成,甲方需要做好项目的采购管理、外包管理,其中采购管理的核心是选择合适...

    一、概述

    在软件外包项目中,甲方(发包商)通过资金或其它资源获取乙方(承包商)的开发服务,以达成其软件需求目标。为了让外包项目按时按质按量完成,甲方需要做好项目的采购管理外包管理,其中采购管理的核心是选择合适的供应商、签订合同,外包管理的核心是过程监控、项目验收。按照外包项目采用的形式和管理方法的不同,可以将外包项目分为项目外包人员外包[1]。

    • 项目外包

    甲方将项目的需求和范围要求发给乙方,候选乙方对此进行报价,然后进行实地考察和分析确认,当甲方认为乙方符合承担条件后,将项目需求和技术资料发给乙方,进行软件开发[1]。项目研发过程涉及的需求、设计、编码、测试、上线、系统支持等项目活动全部由乙方承担。项目外包适合缺少相关专业人员的甲方。

    • 人员外包

    甲方负责项目的组织和管理,雇佣乙方的相关人员参与项目研发的中间环节。常见的人员外包的形式是雇佣乙方的开发人员进行编码工作,人员外包适合拥有具备需求分析、项目管理、技术管理等相关能力的专业人员的甲方。

    近期笔者以甲方项目负责人的身份参与我司一个内部系统的外包项目,项目前期以"项目外包"的形式进行,后期以"人员外包"的形式进行。在本文中笔者将结合项目经历对项目外包、人员外包中外包管理的异同、注意要点进行简要的说明。

    二、项目外包

    笔者在接手项目时, 项目已经进入开发阶段。获取到的项目资料仅仅只是短短几句的项目文档、项目外包合同。通过对业务进行调研,和业务人员沟通,阅读相关文档发现该项目在的规划、需求阶段存在着很大的不足,进而导致了很严重的项目后果。通过对该阶段项目进行复盘,笔者认为在项目立项项目规划需求分析项目验收阶段甲方的外包项目管理需要注意以下几点:

    1. 明确项目干系人

    什么是项目干系人?

    项目干系人又称项目利益相关者,是指积极参与项目实施或完成的,或其利益可能受项目实施或完成情况产生积极或消极影响的个人或组织(如客户、发起人、执行组织或公众),识别干系人是一个持续性的过程[2]。通常参与项目的角色有项目发起人、项目业务方、项目经理、设计人员、开发人员、测试人员等,受项目影响的角色有成果拥有者、系统使用者等。

    在本次的项目过程中,由于在项目规划阶段漏掉了一个重要的业务方,而且笔者因为缺乏干系人的资料导致没有及时干涉,进而导致了项目成果不能满足所有业务方的需要。因此在项目规划阶段明确干系人的人员组成、优先级、期望点,是保障项目定位、需求来源的准确性的必要途径,是进入项目需求阶段的基础

    2. 合理的项目团队组织

    项目团队组织包括人员安排、任务划分、沟通协作项目确认。合理项目团队组织能够明确人员职责,监控项目进程,及时发现问题,降低项目进度和质量失控的风险。在笔者没有介入该项目的前期,乙方项目经理直接和业务需求人员进行沟通,由于业务需求人员缺乏专业知识,导致需求设计不完善、项目节点不合理、项目资源提供不及时等诸多问题。同时在整个项目过程中缺乏正式有效沟通协调机制,导致对进度没有清晰的掌控,无法确认乙方是否充分投入资源。因此笔者认为合理的项目组织需要做到以下几点:

    • 安排专业人员作为项目对接人

    合格的项目对接人需要了解软件开发知识,熟悉项目开发流程,善于交流,又了解业务知识。项目对接人负责对软件外包项目全过程进行全面的监控和协调,以期更好地消除由于信息不对称所产生的一系列项目进度和质量风险,确保软件外包各方能够更有效地履行合同[3]。

    • 建立项目进度跟踪机制

    建立项目进度跟踪机制的目的是监督外包项目的进展情况,确认项目实际进度与合同规定的时间进度表是否相符,评估乙方投入的开发资源是否充分。项目进度跟踪通常以会议、邮件、即时聊天等约定的交流形式定期检查,频率至少1周一次。通过乙方定期提供的项目相关信息,来确认阶段任务完成情况、总结项目问题,检查实际进度是否延迟,评估项目进行的风险,并讨论相关解决方案。

    3. 不可忽视项目的非功能需求

    非功能需求是系统需求的重要组成部分,是影响用户使用体验、产品能否提供高效稳定服务的关键。常见的非功能需求包括性能需求、安全需求、集成需求、可靠性需求、兼容性需求、易用性需求等。在本次外包项目过程中,由于忽略了非功能需求导致了多个项目失误,比如管理后台没有对接单点登录,同时在线用户过多服务器瘫痪,因此在项目规划时不能忽视对非功能需求的需求分析。然而非功能的定义很抽象,如何清晰准确的描述非功能需求是非功能需求分析的关键。通常对于非功能需求的描述是通过量化业务指标、详细具体的规则进行说明,常用到的如下:

    • 性能需求

    对于前台的系统而言,通常以“响应时间”上进行定义,并具体到的某个业务场景[4]。需求描述举例如下[5]:

    • 定位系统从点击到第一个界面显示出来所需要的时间不得超过300毫秒。
    • 在非高峰时间根据编号和名称特定条件进行搜索,可以在3秒内得到搜索结果。

    对于后台的业务管理系统来说,通常以“整体能力上来定义”,并具体到某个业务场景[4]。常见的业务指标包括“并发量、资源使用率、业务量、系统容量”等等[4]。需求描述举例如下[5]:

    • 系统可以同时满足10,000个用户请求,并为25,000个并发用户提供浏览功能。
    • CPU占用率<=50%,内存占用率<=50%。
    • 数据库表行数不超过100万行,数据库最大容量不超过1000GB,磁盘空间至少需要40G以上。
    • 可扩展性需求

    系统的可扩展性就是考虑系统未来为了追加新功能是否方便,便宜,能够满足未来业务量增长的需要。定义扩展性需求时要确定系统的生命周期,然后分析在系统生命期内,业务量变化情况,压力增长情况,以此分析出来的结果,作为扩展性需求,进行定义[4]。系统可扩展可以从系统性能、系统功能两个方面进行考虑,其基本要求是功能扩展时不需要对系统的基础架构进行改动,性能扩展不通过任何代码的更改。在描述系统性能的可扩展需求时应结合性能需求,举例如下:

    • 系统可以在未来需要的情况下,不通过任何代码的更改,对系统性能进行提升,使之中心系统每秒钟能记录25个以上的考勤记录[4]。

    系统功能的可扩展性体现在需求分析与设计阶段是否能有效识别系统可变的需求,不能停留在可扩展的基本原则上,要落实对一个一个功能的分析中,以提供出合理的方案[6]。从业务设计的角度来说,模块化、可复用、较少依赖或耦合是可扩展的原则。

    • 集成需求

    企业内部系统存在多个业务系统,系统之间集成和整合的需求就是集成需求。集成需求主要包括数据对接(系统之间的数据交换和信息传递)、单点登录(多个独立系统统一账号和登录认证)、系统融合( 将多个系统融合在一个系统中,统一账号、权限、应用的管理,最终以一个独立的软件系统存在)[7]。需求描述举例如下:

    • 某某图书管理系统采集##库存管理系统的数据包括库存数据、订单数据。
    • 某某课程管理系统通过与EHR系统实施集成,实现相关基础数据(组织机构、用户数据等)的共享,实施统一身份认证和统一登录界面。
    • 内训管理后台融合到社区管理后台中,统一账号、权限、功能的管理。
    • 兼容性需求

    一般对于前台系统而言,都需要考虑其兼容性。目前最为广泛的前台系统是手机客户端、web端,在考虑系统的兼容性时主要前台的适用平台有哪些,需求描述举例如下。

    • 系统仅支持chrome浏览器,不考虑移动端适配。
    • 移动端需要兼容的操作系统IOS6以上、Andriod6.0以上。
    • 易用性需求

    易用性和产品的用户体验相关,是一组规定或者潜在的用户为使用其软件所需做的努力和对这样的使用所作的评价有关的一组属性[8]。衡量易用性的标准是用户对于系统功能是否容易理解、是否容易学习、是否容易操作,需求描述举例如下:

    • 80%的用户经过培训后,可在5分钟内完成课程创建。
    • 90%的用户完成建课后,需要在5s内知道下一步需要进行什么操作,如课程上线、编辑、查看详情等。

    4. 合理的项目里程碑安排

    项目里程碑安排就制定项目计划,是对项目的进度管理、目标管理,是进度跟踪的关键。项目里程碑就是通过识别项目的软件活动,以软件活动完成时间节点作为项目里程碑。具体的项目计划安排由乙方产品经理负责,甲方需要进行评审,判断其合理性。
    在此次项目中,由于项目的阶段划分、开发计划制定都没有进行严格的审核,项目过程虽然按照业务需求划分成两个阶段,但是没有做相关的阶段验收计划,因此笔者增加了项目阶段验收的环节。项目第一阶段的计划周期过短,中间有法定假日的影响,虽然乙方组织开发人员进行加班,但是只有web端完成,追赶进度的同时导致了严重的质量问题。由于移动端采用的技术方案是以SDK的形式嵌入公司的移动OA应用中,在项目集成过程中产生了严重的类库冲突问题,阻碍了项目进展。因此合理项目计划安排、计划实施过程中需要考虑以下几点:

    • 提前预估项目风险

    在进行项目规划的时候,要充分地平台项目进展过程中可能遇到的风险,针对这些风险制定相应的规避措施,对于容易产生风险的项目任务,需要预留充足的时间。

    • 项目任务的工期要符合项目开发实际

    在很多时候乙方为了中标会向甲方承诺工期,然而实际开发的结果往往会是不能按时交付、完成质量不能满足客户期望。因此对应甲方对接人在乙方完成需求分析后,根据需求规格说明书评审乙方的项目开发计划,如果发现不合理需让乙方调整,确认计划无误后须进行冻结。

    • 划分子项目

    对应涉及多终端、多业务需求的大型项目,可根据业务需求的优先级、系统终端类型,划分多个子项目进行多次验收多次交付,一个阶段没有完成不能进入下一阶段,项目通过多次迭代完成上线验收。采用这种方式能够降低项目风险,提高项目完成质量。

    三、人员外包

    在此次项目的人员外包阶段,外包的开发人员异地开发,因此项目过程中如何协调异地开发人员的开发工作,如果保证需求沟通中无阻碍,就是人员外包面临主要问题。复盘此次的项目经历,笔者认为人员外包需要注意以下几点:

    ###1. 和乙方项目经理沟通

    在项目过程中可能会出现外包人员工作配合度不高,需要安排外包人员加班处理某些任务等问题。遇到这些问题时首先要和乙方的项目经理进行沟通反应问题,或者在告知外包人员的同时告知乙方项目经理。

    ###2. 统一的项目协作平台

    通过在线的项目协作平台,能够方便团队成员直接进行沟通,便于项目经理对项目任务协调和控制,同时记录项目需求、项目决策、需求变更等重要内容。笔者参与的外包项目采用的在线协作平台是wiki+redmine的形式,wiki记录项目需求、项目人员、项目里程碑、会议纪要等内容,redmine进行任务分配、任务跟踪、bug管理。

    四、总结

    软件项目外包管理涉及到很多流程,甲方从项目立项到选择承包商,再到签订合同、跟踪监控,最后成果验收,乙方从项目竞标到竞标成功 ,再到系统策划、需求分析、系统设计、编码测试,最后提交验收,整个项目从开始到收尾,甲方乙方其实是合作者,为了共同的项目目标而走到一起的,虽然整个过程中,难免会遇到很多问题,踩很多坑。
    笔者结合自身的项目经验总结了一些要点,希望能对大家在进行外包项目能够有所帮助,减少弯路,其中难免会有不足之处,请大家批评指正。

    参考资料

    [1] 杨曙贤, 王军辉和张爱国. 软件外包概论. 普通高等教育软件工程“十二五”规划教材. 人民邮电出版社, 2015.
    [2](美)项目管理协会.项目管理知识体系指南(PMBOK指南)第四版.北京:电子工业出版社,2009:23-24.
    [3] 王梅源. 软件外包项目全过程风险管理. 华中科技大学出版社, 2009.
    [4] 非功能需求定义与测试.百度文库, 2011.
    [5] 常见非功能性需求的描述案例.CSDN博客, 2018.
    [6] [我们应当怎样做需求分析:非功能需求.ITeye博客, 2012.]
    (https://www.iteye.com/blog/fangang-1497941)
    [7] 软件系统集成与整合的常见方式.百度文库, 2018.
    [8] 电子工业部标准化研究所.GB/T 16260-1996 信息技术 软件产品评价 质量特性及其使用指南.

    展开全文
  • 禅道-使用禅道来进行项目任务管理

    千次阅读 2018-12-07 10:21:07
       王春生    197002 ...最后编辑:薛才杰 于 2018-07-04 16:18:12 ...简介:禅道简使用方式就是单纯...、创建项目 二、设置团队 三、分解任务 四、管理任务 也许您刚刚看到禅道的界面,心里说,哇,这么多...

    转载自 : https://www.zentao.net/book/zentaopmshelp/49.html

     

     王春生

     

     197002

     

    最后编辑:薛才杰 于 2018-07-04 16:18:12

    简介:禅道简使用方式就是单纯的项目任务管理,创建项目,分解任务。

    也许您刚刚看到禅道的界面,心里说,哇,这么多功能。是不是有些复杂了?我们想说的是,禅道的定位不是那种简单的任务管理软件,而是专业的协同管理软件。研发类的项目管理本身具有其复杂性,所以禅道提供的都是必备的功能。但这并不意味着您必须按照禅道的流程来使用,完全可以按照自己的实际情况来使用禅道。下面让我们来看下使用禅道的简单方式。

    一、创建项目

    添加新项目的入口有多个,进入项目视图,可以在左侧1.5级导航的下拉菜单中直接点击“添加项目”。或者在项目主页的项目总览区块中点击“添加项目”。

     

    在项目添加的页面中,设置项目名称、代号、起止时间、可用工作日、团队名称、和项目描述等字段。其中关联产品是可以为空,也可以多选。

    二、设置团队

    点击保存按钮,会提示项目创建成功,然后可以选择设置团队。或者从项目视图中的团队菜单,也可以进行项目的团队管理。

     

    在维护项目团队的时候,需要选择都是哪些用户可以参与到这个项目中,同时需要设置这个用户在本项目中的角色(角色可以随便设置,比如风清扬,冬瓜一号等)。可用工作日和可用工时每天需要仔细设置。通常来讲,一个人不可能每天8小时投入,也不可能一星期七天连续投入。设置完毕之后,系统会自动计算这个项目总得可用工时。

     

    三、分解任务

    设置了团队之后,下一步操作就是创建任务。

     

    • 在创建任务的时候,指派给是从项目团队成员中读取。
    • 姓名列表中的首字母可以用来快速筛选用户。
    • 任务的优先级、预计工时(单位小时)都需要进行设置。
    • 如果需要设置任务必须在某一个时间点截止,可以设置截止日期。
    • 可以上传附件。

    四、管理任务

    任务分解完毕之后,每个人就非常清楚自己做什么事情。所以项目启动之后,对于项目团队的成员来讲,他要做的事情就是更新任务的进度和状态。


    任务的列表: 在任务的列表页面,可以看到系统中所有的任务列表,可以通过各种标签方便的进行筛选。点击某一个任务的名称进入详情页面。

    任务的详情页面: 在任务的详情页面可以看到任务的详细信息,包括历次的修改记录等信息。同时也给出了各种操作的按钮。

    开始任务: 开始某一个任务的时候,可以设置已经消耗的时间和预计剩余的时间。单位都是工时。

    更新任务工时: 点击操作栏里的“工时”按钮,通过更新工时消耗,来管理任务执行进度。

    完成任务: 完成任务的时候,需要设置下已经消耗的时间。

    关闭任务:任务完成之后,点击操作栏里的“关闭”按钮,将该任务关闭,这个任务就结束了。

     

    上述就是使用禅道来进行简单的项目和任务管理,怎么样?还是很简单的吧。下面让我们来看下只使用禅道来进行bug的跟踪管理。

     

    关键词 :项目管理软件,禅道最简使用流程

     发表评论

    评论列表

     yue 2018-11-27 11:53:12

    项目关联为空的话,无法提bug

     王林 2018-11-27 15:12:59

    禅道中bug是在产品下进行管理的,可以创建产品,然后在测试-bug下提交bug。所属项目不是必填的

     清秋 2018-11-15 18:23:30

    填写工时时,有的提示“当前任务只有closed才可以记录工时“;有的没有提示,只是显示已经填写的工时,但是并地方填写。

     王林 2018-11-16 08:36:29

    这个应该是已关闭的多人任务。
    已关闭的任务不应该在进行维护了,需要记录工时,可以重新激活任务后进行录入

     苏振阳 2018-11-09 10:43:59

    1.禅道中有没有批量删除不在使用的项目或者已关闭的项目呢? 2.在文档中建立了一个文件夹,可以在文件夹中继续建立文件夹吗?可以建立几级子文件夹

     王林 2018-11-09 15:45:05

    1、没有批量删除项目的功能
    2、可以点击文档库在文档库右下角点击维护分类。

     小麦 2018-10-31 16:28:25

    能不能看到哪个任务是按规定时间完成,哪个是延期没有完成,超时了。还有工时统计,哪个项目总工用了多少工时,能看到吗

     王林 2018-10-31 16:41:25

    1、可以在项目-任务页面搜索一下实际完成时间大于截至日期的任务
    2、项目-概况页面可以看到项目的总消耗工时

     安女士 2018-10-25 16:55:07

    你好,请问任务可以同时指派给多个人吗?怎样才能指给多个人?

     禅道-Bee 2018-10-25 17:00:16

    近期的禅道版本,增加了多人任务、子任务功能可以了解下:https://www.zentao.net/book/zentaopmshelp/130.html

     yangyy 2018-09-04 18:56:04

    你好,目前我们使用禅道,遇到一个问题,就是任务调整比较麻烦。添加好的任务,如果计划有变化,临时增加了一些任务,那么后续的任务不能自动匹配刷新。只能手动调整。效率很低,请问,有什么插件,或者这个可以跟project关联吗?

     王林 2018-09-05 08:58:30

    项目分解完成任务后,就不建议再对项目中的任务进行调整了,如果有新的任务建议关联到下期项目进行完成,如果对项目分解任务把控不准确,可以试下缩短项目周期。

     石洋洋 2018-09-05 08:59:20

    任务的日期联动是会导致一些额外的问题的,禅道是根据敏捷开发设计的,一个项目的周期一般是 2周-2个月,在项目进行过程中 应该尽量避免临时加需求加任务的,这样会影响项目的进度。可以把需要安排的内容放到下一个计划中实现,如果对时间有要求可以缩短项目的周期,比如一周一个项目。

     melissa 2018-09-01 23:11:35

    为什么 我的界面没有“”项目‘’显示?

     王林 2018-09-03 09:14:59

    1、看下组织-权限中用户所在权限分组的视图维护和权限维护中有分配用户访问项目的权限吗?
    2、看下后台-自定义-流程中是否选择的其他的流程显示
    3、看下自定义导航栏是否将项目模块隐藏了?

     多多 2018-08-24 16:06:58

    可以用禅道只进行项目管理吗?不关联产品

     王林 2018-08-24 16:29:17

    可以在后台-自定义-工作方式中切换为任务管理工具。
    注意这个切换是全局的。

     林夏夕 2018-08-17 17:51:43

    项目创建并启动后,醒目名称还可以修改吗?怎么修改?

     马超 2018-08-17 17:53:11

    可以修改,在项目 - 概况 编辑修改

     陶子 2018-08-17 15:31:23

    为什么我的禅道里面只上面,产品后面没有项目啊

     王林 2018-08-17 15:35:24

    可以使用超级管理员登录禅道看下有吗。
    是否是权限设置的问题。

    1/11  

    展开全文
  •  在一个软件研发项目的管理实践项目任务的分解一直是个很重要的工作,但是不同的项目经理这个问题的操作方式又常常会千差万别,其中个很常见的分歧在于,是横向分解还是纵向分解?本文试图对此进行一个...
  • java项目中定时任务之Quartz的应用

    千次阅读 2013-12-27 11:13:36
    我目前接触到的quartz只是我做的java项目中定时执行任务,我的项目因为是spring的基础上搭建的想要整合quartz非常的简单。 对于非spring项目的应用,它也很强大因为我没有实际测试过不做介绍。如果有需要的可以...
  • 个完整的项目除了包含不同阶段的细分的任务之外,还需要项目负责人\经理为每个任务分配所需要的资源,不限于人力资源,成本或者设备等资源,以此来衡量该项目资源储备是否充足,预算是否超过预期标准,设备是否...
  • 我觉得对于很多PM而言,这个问题应该都说很亲切,反正我是很多项目中都有遇到,无论是前期自己甲方这边的需求团队提交业务需求方案,...(2)乙方成员(自己项目实施过程)不能按约定时间完成任务; 【甲方不能按时完...
  • 面试的时候总被问XXX项目中你遇到了什么问题,怎么解决的?是时候给自己的项目做个总结了。
  • 就像你的脑海已经有了块块”拼图“(机器学习技术),你却不知道如何讲他们拼起来应用实际的项目中。如果你也遇见过同样的问题,那么这篇文章应该是你想要的。本系列文章将介绍个针对真实世界实际数据集的...
  • Jenkins任务远程触发另个jenkins任务

    千次阅读 2019-01-24 16:45:56
    2、远程机器jenkins项目配置:需要选中参数化构建过程,并设置参数名默认值(本地机子项目远程触发时需要用到该参数) 3、远程jenkins构建触发器需要添加触发远程构建身份令牌(本地机子触发该项目构建时的token...
  • 如何做好项目管理任务分配

    千次阅读 2017-04-26 14:11:12
    项目管理工具我工作的10多年,使用过不少的项目管理系统,Excel, Microsoft Project, dotProject, Redmine, Jira, Teambition, Worktile, Tello…。比我谈过的女朋友还多。这里不讲哪个工具更优秀,只能说应人而...
  • 但除了使用基本的日程安排工具以外,项目经理怎样才能权衡相互矛盾的要求或是有足够的时间来应付没有预料到的、最佳计划构成威胁的事情?这篇文章提供了一些复杂的日程安排技巧,可以用来区分优先级、明确价值目标...
  •  要有效地进行进度控制,必须影响进度的因素进行分析,事先或及时采取必要的措施,尽量缩小计划进度与实际进度的偏差,实现对项目的主动控制。软件开发项目中影响进度的因素很多,如人为因素、技术因素、资金因素...
  • WIN7确实方便,尤其它的超级任务栏,它的开始菜单“最近打开程序”的内容XP差不多,但就开始菜单超级任务垃的“最近打开文件”的管理来说,比XP强多了。但是对于刚从XP转型过来的用户来说,这个“最近打开文件...
  • 由于公司的项目是分开的,刚到公司其它人都做其它的项目,所以这个SMS项目交到我人手上。由我写个中间SMS平台用于支持服务于其它项目。用于短信的接收发送以及发送成功,失败,响应的系列处理。做了个...
  • 项目管理之任务分配

    千次阅读 2012-09-30 22:21:50
    项目需求确定了(需求这个东西永远没有确定的哪天,时时刻刻都是变化,但是经理认为确定了那就是确定了:P),然后项目经理给了份需求文档就算真是开始开发了。大致用了天的时间数据库就由个开发人员...
  • 面板生成对应的看板 2.编辑项目 编辑项目信息 设置项目版本 添加功能模块 关联工作流 可以不同类型的问题关联自定义的工作流,这里举例,将故障类问题关联到自定义的testworkflow工作...
  • Quartz,水晶、石英,个简单朴素有美丽的名字,Java程序界,Quartz大名鼎鼎,很多Java应用几乎都集成或构建了个定时任务调度系统,Quartz是个定时任务调度框架。 何为定时任务调度框架?简而言之,它可以...
  • Trello进行时间和项目的管理

    千次阅读 2012-02-01 14:39:56
    现在工作或学习时,会用番茄工作法pomodroido(安卓上面的番茄钟)来梳理执行任务,这种方法用来读书或者进行个人任务我非常有用,由于次只做任务,能够更加专注于当前工作上,排除了各种外界干扰中断
  • 炸裂!手摸手教你如何吃透个 Java 项目,yyds

    万次阅读 多人点赞 2021-06-11 08:24:07
    先说一下大多数新手的情况:就是着视频敲 Java 项目,其中遇到的 BUG 还能解决,但就是每次敲完项目,就感觉很空虚,项目里面的知识点感觉懂了但又好像没懂,应该怎样才能掌握项目所用的知识点呢?...
  • 定时任务框架Quartz-()Quartz入门与Demo搭建

    万次阅读 多人点赞 2018-07-10 13:57:07
    Quartz是OpenSymphony开源组织Job scheduling领域又个开源项目,完全由Java开发,可以用来执行定时任务,类似于java.util.Timer。但是相较于Timer, Quartz增加了很多功能: 持久性作业 - 就是保持调度...
  • 软件工程项目进行管理的过程, WBS(WORK BREAKDOWN STRUATURE)工作(任务)分解结构作为项目管理的种基本方法正在逐渐的走向成熟, 因为无论计划阶段还是执行阶段,WBS 都是个有用的综合工具, 而且其应用...
  • 解读项目经理在项目中的作用

    千次阅读 2020-05-04 07:30:20
    项目次性的整体任务,有统一的目标,需要有专门的负责人才能保证其目标的实现。这个负责人就是项目经理,他是企业在项目上负责管理履行承包合同的委托代理人。 项目经理是项目的现场管理最高负责人...
  • 开始开发之前,我们需要知道每个版本有哪些任务,每个任务需要多少时间,以及谁负责这个项目。甘特图能很好的展示这几个问题。本文记录如何使用WPS来计划分配任务以及绘制甘特图。输入任务和开始时间的日期号 ...
  • svn对项目权限进行管理

    万次阅读 2018-11-10 08:59:52
    svn对项目权限进行管理
  • 1.将项目进行分解,分解成小任务 2.接着更具成员的能力特长分配任务 3.任务的分派要比较均衡,不要有的忙死有的闲死 4.将分派的结果发给成员,并开会沟通,看有什么意见建议,有时候需要调整任务分配 5.根据工期...
  • 我们这里分析的是已经发生的时候的风险处理(这个应该是在项目管理的风险管理列表里面的项), 以及风险没有发生之前的一些预防措施。 以下的讨论会比较关注IT的项目管理,也部分适用于其他项目。 无法按期完成...
  • 1.团队开发时,需要一些项目-任务管理工具来分配控制项目进度状态. 2.可选的项目管理工具有: Jira 收费 自带数据库,可配置mysql 功能强大(支持插件) 易用 Java 性能高 复杂 ...
  • 前提注意:配置文件如果 ... 以前项目一直使用Quartz的定时任务,虽然其功能强大,但是配置文件极其复杂,并且个class下只能执行个方法(貌似是)。定时任务多了以后对于维护xml配置文件时件极为头疼的事情。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 748,792
精华内容 299,516
关键字:

在任务和项目中进行一对一