Job作业调度(导入文件多条商品,在前台进度条显示)

我接触的实际情况是excel文件导入多条商品功能,但是导入可能花费一定的时间,我们就想根据导入的数据做一个进度条,并且可以显示导入第几条,每导入一条,就显示相应的信息。

这里我们就用了作业调度,通过一个Job不断的运行,将我们的‘作业’放在job中,进行一个监控和访问。

我们使用quartz这一技术

那么我们需要一个作业调度器,然后set相应的作业,进行操作。

获取quartz的核心类

Scheduler scheduler = ApplicationContextUtils.getBean(DEFAULT_SCHEDULER_ID);

进行多任务的分组(相当于一个载体,用来存,是哪个作业,作业名称,返回的结果也在其中)

JobScheduleHandler handler = new JobScheduleHandler((String) params.get(ImpexConstants.PN_PLUGINNAME), jobCls.getSimpleName() + UUIDGenerator.getUUID());

// 为了支持并发多任务需要制定不同分组

我们new 一个作业

JobKey jobKey = new JobKey(handler.getName(), handler.getGroup());

如果作业调度已经执行过的作业,直接将调度去set到handle中 (context是作业任务的上下文),这里主要是有一些参数返回值,放到handler。

if (scheduler.checkExists(jobKey)) {
        for (JobExecutionContext context : scheduler.getCurrentlyExecutingJobs()) {
          if (jobKey.equals(context.getJobDetail().getKey())) {
            handler.setScheduled(context.getFireTime());
            break;
          }
        }

如果是新的任务,需要将参数设置到上下文。

       (jobCls是具体实现的作业)

        JobDetail jobDetail = JobBuilder.newJob(jobCls).withIdentity(jobKey).build();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
          jobDetail.getJobDataMap().put(entry.getKey(), entry.getValue());
        }
        jobDetail.getJobDataMap().put(ImpexConstants.PN_OPERCTX, JsonUtil.objectToJson(operCtx));
        Trigger trigger = TriggerBuilder.newTrigger().startNow().build();  //此处就是开始执行作业
        scheduler.scheduleJob(jobDetail, trigger);
最后将执行后的handler返回,这里返回到界面,界面就可以收到改执行时间进行结构返回,包括第几条,等各种信息。
        handler.setScheduled(StringUtil.toDate(
          new SimpleDateFormat(JsonUtil.DATE_FORMAT).format(handler.getScheduled()),
          StringUtil.DATE_FORMATS[1]));
        return handler;


这里是springMVC接受请求的controller这样收到请求和执行的

 @RequestMapping(value = "importForStandard", method = RequestMethod.POST)
  public @ResponseBody JobScheduleHandler importForStandard(@RequestBody ImpexParams params)
      throws Hdpos4ServiceException {
    Map<String, Object> paramsMap = new HashMap<String, Object>();
    paramsMap.put(ImpexConstants.PN_LANG, Hdpos4Util.getSysLang());
    paramsMap.put(ImpexConstants.PN_PLUGINNAME, params.getPluginName());
    paramsMap.put(ImpexConstants.PN_MAXCOUNT, params.getMaxCount());
    paramsMap.put(ImpexConstants.PN_FILEURLS, params.getFileUrls());

    return JobScheduler.schedule(DiralcImportJob.class, paramsMap, getBeanOperateContext());
  }

我们会Return也就是上面的handler

里面的DiralcImportJob,就是具体要执行的job(作业)


而作业当中,比如如何拿到参数等等需要一些基类,将context上下文设置进去。这些公共的方法就在基类中实现。

其中包含一些中断功能

public abstract class AbstractJob implements InterruptableJob {

  private static final Logger logger = LoggerFactory.getLogger(AbstractJob.class);

  private JobExecutionContext context;

  @Override
  public void execute(JobExecutionContext context) throws JobExecutionException {
    JobContext.initial(context);
    this.context = context;
    try {
      preProcess();

      doExecute();

      postProcess(JobInstanceResult.completed, null);
    } catch (InterruptedException e) {
      postProcess(JobInstanceResult.interrupted, e);
    } catch (Exception e) {
      postProcess(JobInstanceResult.aborted, e);
    } finally {
      JobContext.free();
    }
  }

  /**
   * 执行作业。
   */
  protected abstract void doExecute() throws InterruptedException, Exception;

  /**
   * 取得作业结果通知器对象。<br>
   * 子类开发者可以通过重写此方法,实现发出作业执行结果通知的功能。
   * 
   * @return 返回null将不会发出通知。
   */
  protected JobNotifier getNotifier() {
    return null;
  }

  @Override
  public void interrupt() throws UnableToInterruptJobException {
    logger.info("Try to interrupt the job.");
    JobContext.interrupt(context);
  }

  /**
   * 预处理。在{@link #doExecute()}之前被调用。
   */
  protected void preProcess() {
    assert context != null;
    saveForStartingJob(context);
  }

  /**
   * 后处理。在{@link #doExecute()}之后被调用。
   * 
   * @param result
   *          作业执行结果。禁止传入null。
   * @param e
   *          异常对象。
   * @throws IllegalArgumentException
   *           当参数result为null时抛出。
   */
  protected void postProcess(JobInstanceResult result, Exception e) throws IllegalArgumentException {
    assert context != null;
    Assert.assertArgumentNotNull(result, "result");

    log(result, e);

    saveForFinishingJob(context, result);

    notify(result, e);
  }

  private void log(JobInstanceResult result, Exception e) {
    if (JobInstanceResult.completed.equals(result)) {
      logger.info("Job Completed.");
    } else if (JobInstanceResult.interrupted.equals(result)) {
      logger.info("Job Interrupted.");
    } else if (JobInstanceResult.aborted.equals(result)) {
      logger.error("Job Aborted.", e);
    } else {
      assert false;
    }
  }

  private void saveForStartingJob(JobExecutionContext context) {
    assert context != null;
    try {
      PJobInstance jobInstance = new PJobInstanceConverter().convert(context);
      PJobInstanceDao jobInstanceDao = DaoFactory.getInstance().getJobInstanceDao();
      jobInstanceDao.save(jobInstance);
    } catch (Exception e) {
      logger.error("Fail to save for starting job.", e);
    }
  }

  private void saveForFinishingJob(JobExecutionContext context, JobInstanceResult result) {
    assert context != null;
    assert result != null;
    try {
      PJobInstance jobInstance = new PJobInstanceConverter().convert(context);

      jobInstance.setState(JobInstanceState.over);
      jobInstance.setFinishedAt(new Date());
      jobInstance.setResult(result);

      PJobInstanceDao jobInstanceDao = DaoFactory.getInstance().getJobInstanceDao();
      jobInstanceDao.save(jobInstance);
    } catch (Exception e) {
      logger.error(MessageFormat.format("Fail to save for finishing job: {0}.", result), e);
    }
  }

  private void notify(JobInstanceResult result, Exception caught) {
    assert result != null;
    JobNotifier notifier = getNotifier();
    if (notifier == null) {
      return;
    }
    try {
      notifier.nodify(result, caught, context);
    } catch (Exception e) {
      logger.error("Fail to notify.", e);
    }
  }

}







      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值