简单的quartz 可视化监听管理界面

spring-quartz。

导包、配置,不在此介绍。

简单的quartz管理界面,包括触发器的暂停、恢复、删除、修改(暂无),任务的运行、触发添加、创建,删除。

扩展内容:日志的管理,添加和创建触发器的操作(暂无实现)

本文原创,禁止转载。

扩展内容(暂不实现)

 

前端代码:

<%--
  Created by IntelliJ IDEA.
  User: ttttt
  Date: 2017/5/31
  Time: 15:43
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
    <title>Title</title>
    <link rel="stylesheet" type="text/css" href="/bootstrap/css/bootstrap.min.css">
    <script type="text/javascript" src="/js/jquery-2.1.1.min.js"/>
    <script type="text/javascript" src="/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
<h1>调度详情</h1>
<table id="table_report" class="table table-striped table-bordered table-hover">
    <thead>
    <tr>
        <!-- th class="text-center">序号</th-->
        <th class="text-center">任务组名称</th>
        <th class="text-center">定时任务名称</th>
        <th class="text-center">触发器组名称</th>
        <th class="text-center">触发器名称</th>
        <%--<th class="text-center">任务类名</th>--%>
        <th class="text-center">触发器描述</th>
        <th class="text-center">时间表达式</th>
        <th class="text-center">任务状态</th>
        <th class="text-center">开始时间</th>
        <th class="text-center">上次重启时间</th>
        <th class="text-center">上次执行时间</th>
        <%--<th class="text-center">下次运行时间</th>--%>
        <th class="text-center">操作</th>
    </tr>
    </thead>
    <tbody>
    <!-- 开始循环 -->
    <c:choose>
        <c:when test="${not empty jobInfos && jobInfos.size()>0}">
            <c:forEach items="${jobInfos}" var="var" varStatus="vs">
                <tr>
                    <td class='text-center' style="width: auto;">${var.jobGroup}</td>
                    <td class='text-center' style="width: auto;">${var.jobName}</td>
                    <td class='text-center' style="width: auto;">${var.triggerGroupName}</td>
                    <td class='text-center' style="width: auto;">${var.triggerName}</td>
                    <%--<td class='text-center' style="width: auto;">${var.jobClass}</td>--%>
                    <td class='text-center' style="width: auto;">${var.description}</td>
                    <td class='text-center' style="width: auto;">${var.cronExpr}</td>
                    <td class='text-center' style="width: auto;">
                        <c:if test="${var.jobStatus == 'NONE'}">
                            <span class="label">未知</span>
                        </c:if>
                        <c:if test="${var.jobStatus == 'NORMAL'}">
                            <span class="label label-success arrowed">正常运行</span>
                        </c:if>
                        <c:if test="${var.jobStatus == 'PAUSED'}">
                            <span class="label label-warning">暂停状态</span>
                        </c:if>
                        <c:if test="${var.jobStatus == 'COMPLETE'}">
                            <span class="label label-important arrowed-in">完成状态</span>
                        </c:if>
                        <c:if test="${var.jobStatus == 'ERROR'}">
                            <span class="label label-info arrowed-in-right arrowed">错误状态</span>
                        </c:if>
                        <c:if test="${var.jobStatus == 'BLOCKED'}">
                            <span class="label label-danger">锁定状态</span>
                        </c:if>
                    </td>
                    <td class='text-center' style="width: auto;"><fmt:formatDate value="${var.startTime}"
                                                                                      pattern="yyyy-MM-dd HH:mm:ss"/></td>
                    <td class='text-center' style="width: auto;"><fmt:formatDate value="${var.reStartTime}"
                                                                                 pattern="yyyy-MM-dd HH:mm:ss"/></td>
                    <td class='text-center' style="width: auto;"><fmt:formatDate value="${var.previousFireTime}"
                                                                                 pattern="yyyy-MM-dd HH:mm:ss"/></td>
                        <%--<td class='text-center' style="width: auto;"><fmt:formatDate value="${var.nextFireTime}"--%>
                        <%--pattern="yyyy-MM-dd HH:mm:ss"/></td>--%>
                    <td class='text-center' style="width: auto;">
                        <a class="btn btn-sm btn-warning" onclick="pauseJob('${var.triggerName}','${var.triggerGroupName}');">暂停</a>
                        <a class="btn btn-sm btn-success" onclick="resumeJob('${var.triggerName}','${var.triggerGroupName}');">恢复</a>
                        <a class="btn btn-sm btn-info" onclick="triggerJob('${var.jobName}','${var.jobGroup}');">修改</a>
                        <a class="btn btn-sm btn-danger" onclick="deleteJob('${var.triggerName}','${var.triggerGroupName}');">删除</a>
                    </td><!-- cron,jobName,jobGroupName,triggerName,triggerGroupName -->
                </tr>
            </c:forEach>
        </c:when>
        <c:otherwise>
            <tr class="main_info">
                <td colspan="100" class="text-center">没有相关数据</td>
            </tr>
        </c:otherwise>
    </c:choose>
    </tbody>
</table>
<h1>任务详情</h1>
<table id="table_detail_report" class="table table-striped table-bordered table-hover">
    <thead>
    <tr>
        <!-- th class="text-center">序号</th-->
        <th class="text-center">任务组名称</th>
        <th class="text-center">任务名称</th>
        <th class="text-center">任务类名</th>
        <th class="text-center">任务描述</th>
        <th class="text-center">持久性</th>
        <th class="text-center">禁止并发</th>
        <th class="text-center">数据更新</th>
        <th class="text-center">恢复性</th>
        <th class="text-center">关联调度器数量</th>
        <th class="text-center">操作</th>
    </tr>
    </thead>
    <tbody>
    <!-- 开始循环 -->
    <c:choose>
        <c:when test="${not empty jobDetailInfos && jobDetailInfos.size()>0}">
            <c:forEach items="${jobDetailInfos}" var="var" varStatus="vs">
                <tr>
                    <td class='text-center' style="width: auto;">${var.jobGroup}</td>
                    <td class='text-center' style="width: auto;">${var.jobName}</td>
                    <td class='text-center' style="width: auto;">${var.jobClass}</td>
                    <td class='text-center' style="width: auto;">${var.description}</td>
                    <td class='text-center' style="width: auto;">
                        <c:if test="${var.duration}">
                            是
                        </c:if>
                        <c:if test="${!var.duration}">
                            否
                        </c:if>
                    </td>
                    <td class='text-center' style="width: auto;">
                        <c:if test="${var.concurrentExectionDisallowed}">
                            是
                        </c:if>
                        <c:if test="${!var.concurrentExectionDisallowed}">
                            否
                        </c:if>
                    </td>
                    <td class='text-center' style="width: auto;">
                        <c:if test="${var.persistJobDataAfterExecution}">
                            是
                        </c:if>
                        <c:if test="${!var.persistJobDataAfterExecution}">
                            否
                        </c:if>
                    </td>
                    <td class='text-center' style="width: auto;">
                        <c:if test="${var.requestsRecovery}">
                            是
                        </c:if>
                        <c:if test="${!var.requestsRecovery}">
                            否
                        </c:if>
                    </td>
                    <td class='text-center' style="width: auto;">${var.triggerCount}</td>
                    <td class='text-center' style="width: auto;">
                        <a class="btn btn-sm btn-success"
                           onclick="triggerJob('${var.jobName}','${var.jobGroup}');">运行一次</a>
                        <a class="btn btn-sm btn-warning" href="/quartz/addJobTrigger?jobName=${var.jobName}&&jobGroup=${var.jobGroup}">添加调度</a>
                        <a class="btn btn-sm btn-info" href="/quartz/addJobTrigger?jobName=${var.jobName}&&jobGroup=${var.jobGroup}">创建调度</a>
                        <a class="btn btn-sm btn-danger" onclick="deleteJobDetail('${var.jobName}','${var.jobGroup}');">删除</a>
                    </td><!-- cron,jobName,jobGroupName,triggerName,triggerGroupName -->
                </tr>
            </c:forEach>
        </c:when>
        <c:otherwise>
            <tr class="main_info">
                <td colspan="100" class="text-center">没有相关数据</td>
            </tr>
        </c:otherwise>
    </c:choose>
    </tbody>
</table>
<h1>添加/修改 调度</h1>
<form class="form-horizontal" action="quartzAdd/add">
    <div class="form-group">
        <label for="jobName" class="col-sm-1 control-label">任务名称</label>
        <div class="col-sm-3">
            <input type="text" class="form-control" id="jobName" disabled placeholder="任务名称" value="${jobDetailInfo.jobName}">
        </div>
    </div>
    <div class="form-group">
        <label for="jobGroupName" class="col-sm-1 control-label">任务组名称</label>
        <div class="col-sm-3">
            <input type="text" class="form-control" id="jobGroupName" disabled placeholder="任务组名称" value="${jobDetailInfo.jobGroup}">
        </div>
    </div>
    <div class="form-group">
        <label for="jobClass" class="col-sm-1 control-label">任务类</label>
        <div class="col-sm-3">
            <input type="text" class="form-control" id="jobClass" disabled placeholder="任务类" value="${jobDetailInfo.jobClass}">
        </div>
    </div>
    <c:forEach items="${jobDetailInfo.jobDataMap}" var="var" varStatus="vs">
        <div class="form-group">
            <label for="jobData${vs.count}" class="col-sm-1 control-label">${var.key} (初始化)</label>
            <div class="col-sm-3">
                <input type="text" class="form-control" id="jobData${vs.count}" disable placeholder="当前任务值:${var.value}">
            </div>
        </div>
    </c:forEach>
    <div class="form-group">
        <label for="triggerName" class="col-sm-1 control-label">触发器名称</label>
        <div class="col-sm-3">
            <input type="text" class="form-control" id="triggerName" placeholder="触发器名称">
        </div>
    </div>
    <div class="form-group">
        <label for="triggerGroupName" class="col-sm-1 control-label">触发器组名称</label>
        <div class="col-sm-3">
            <input type="text" class="form-control" id="triggerGroupName" placeholder="触发器组名称">
        </div>
    </div>
    <div class="form-group">
        <label for="cron" class="col-sm-1 control-label">cron表达式</label>
        <div class="col-sm-3">
            <input type="text" class="form-control" id="cron" placeholder="例如: 0 0/5 * 6L * 1,2 ?">
        </div>
    </div>
    <div class="form-group">
        <label class="col-sm-1 control-label">是否立即执行</label>
        <div class="col-sm-3">
            <label class="radio-inline">
                <input type="radio" name="radio" id="inlineRadio1" value="1"> 是
            </label>
            <label class="radio-inline">
                <input type="radio" name="radio" id="inlineRadio2" value="0"> 否
            </label>
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-offset-1 col-sm-3">
            <button type="submit" class="btn btn-default">添加调度</button>
        </div>
    </div>
</form>
<h1>创建调度</h1>
<form class="form-horizontal" action="quartzAdd/add">
    <div class="form-group">
        <label for="jobName1" class="col-sm-1 control-label">任务名称</label>
        <div class="col-sm-3">
            <input type="text" class="form-control" id="jobName1" placeholder="任务名称">
        </div>
    </div>
    <div class="form-group">
        <label for="jobGroupName1" class="col-sm-1 control-label">任务组名称</label>
        <div class="col-sm-3">
            <input type="text" class="form-control" id="jobGroupName1" placeholder="任务组名称">
        </div>
    </div>
    <div class="form-group">
        <label for="jobClass1" class="col-sm-1 control-label">任务类</label>
        <div class="col-sm-3">
            <input type="text" class="form-control" id="jobClass1" disabled placeholder="任务类" value="${jobDetailInfo.jobClass}">
        </div>
    </div>
    <div class="form-group">
        <label for="triggerName1" class="col-sm-1 control-label">触发器名称</label>
        <div class="col-sm-3">
            <input type="text" class="form-control" id="triggerName1" placeholder="触发器名称">
        </div>
    </div>
    <div class="form-group">
        <label for="triggerGroupName1" class="col-sm-1 control-label">触发器组名称</label>
        <div class="col-sm-3">
            <input type="text" class="form-control" id="triggerGroupName1" placeholder="触发器组名称">
        </div>
    </div>
    <div class="form-group">
        <label for="cron1" class="col-sm-1 control-label">cron表达式</label>
        <div class="col-sm-3">
            <input type="text" class="form-control" id="cron1" placeholder="例如: 0 0/5 * 6L * 1,2 ?">
        </div>
    </div>
    <div class="form-group">
        <label class="col-sm-1 control-label">是否立即执行</label>
        <div class="col-sm-3">
            <label class="radio-inline">
                <input type="radio" name="radio" id="inlineRadio11" value="1"> 是
            </label>
            <label class="radio-inline">
                <input type="radio" name="radio" id="inlineRadio12" value="0"> 否
            </label>
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-offset-1 col-sm-3">
            <button type="submit" class="btn btn-default">创建调度</button>
        </div>
    </div>
</form>
<br/>
<script>
    function deleteJobDetail(jobName, jobGroup) {
        if(confirm("是否删除该任务详情。")){
            $.ajax({
                type: "POST",
                url: "/quartz/deleteJobDetail",
                data: {"jobName": jobName, "jobGroup": jobGroup},
                success: function (data) {
                    if(data){
                        location.reload();
                    }else{
                        alert("删除失败。");
                    }
                },
                fail: function () {
                    alert("操作失败。");
                }
            });
        }
    }
    function triggerJob(jobName, jobGroup) {
        if(confirm("是否立即运行一次。")){
            $.ajax({
                type: "POST",
                url: "/quartz/triggerJob",
                data: {"jobName": jobName, "jobGroup": jobGroup},
                success: function (data) {
                    if(data){
                        location.reload();
                    }else{
                        alert("删除失败。");
                    }
                },
                fail: function () {
                    alert("操作失败。");
                }
            });
        }
    }
    function deleteJob(triggerName, triggerGroup) {
        if(confirm("是否删除该任务。")){
            $.ajax({
                type: "POST",
                url: "/quartz/deleteJob",
                data: {"triggerName": triggerName, "triggerGroup": triggerGroup},
                success: function (data) {
                    if(data){
                        location.reload();
                    }else{
                        alert("删除失败。");
                    }
                },
                fail: function () {
                    alert("操作失败。");
                }
            });
        }
    }
    function resumeJob(triggerName, triggerGroup) {
        $.ajax({
            type: "POST",
            url: "/quartz/resumeJob",
            data: {"triggerName": triggerName, "triggerGroup": triggerGroup},
            success: function (data) {
                if(data){
                    location.reload();
                }else{
                    alert("恢复失败。");
                }
            },
            fail: function () {
                alert("操作失败。");
            }
        });
    }
    function pauseJob(triggerName, triggerGroup) {
        $.ajax({
            type: "POST",
            url: "/quartz/pauseJob",
            data: {"triggerName": triggerName, "triggerGroup": triggerGroup},
            success: function (data) {
                if(data){
                    location.reload();
                }else{
                    alert("暂停失败。");
                }
            },
            fail: function () {
                alert("操作失败。");
            }
        });
    }
</script>
</body>
</html>

Controllere代码:

package com.sky.controller;

import com.sky.bean.JobDetailManage;
import com.sky.bean.JobEntity;
import com.sky.util.QuartzManager;
import com.sky.util.QuartzUtils;
import com.sun.istack.internal.NotNull;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @author sky
 */
@Controller
public class JobController {

    private Scheduler quartzScheduler;

    @RequestMapping("/quartz")
    public ModelAndView quartz() {
        ModelAndView mv = new ModelAndView();
        mv.setViewName("quartz");
        JobKey jobKey = JobKey.jobKey("hello4", "group1");
        try {
            mv.addObject("jobInfos", getSchedulerJobInfo());
            mv.addObject("jobDetailInfos", getJobDetailInfos());
            mv.addObject("jobDetailInfo", getJobDetailInfo(jobKey));
        } catch (SchedulerException e) {
        }
        return mv;
    }

    //暂停任务
    @PostMapping("quartz/pauseJob")
    @ResponseBody
    public boolean pauseJob(@NotNull String triggerName, @NotNull String triggerGroup) {
        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
        try {
            quartzScheduler.pauseTrigger(triggerKey);
        } catch (SchedulerException e) {
            System.out.println(e.getMessage());
        }
        return true;
    }

    //恢复任务
    @PostMapping("quartz/resumeJob")
    @ResponseBody
    public boolean resumeJob(@NotNull String triggerName, @NotNull String triggerGroup) throws Exception {
        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
        quartzScheduler.resumeTrigger(triggerKey);
        return true;
    }

    //删除任务
    @PostMapping("quartz/deleteJob")
    @ResponseBody
    public boolean deleteJob(@NotNull String triggerName, @NotNull String triggerGroup) throws Exception {
        JobKey jobKey = JobKey.jobKey(triggerName, triggerGroup);
        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
        quartzScheduler.pauseTrigger(triggerKey);
        return quartzScheduler.unscheduleJob(triggerKey);
    }

    //立即运行任务
    @PostMapping("quartz/triggerJob")
    @ResponseBody
    public boolean triggerJob(@NotNull String jobName, @NotNull String jobGroup) throws Exception {
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        quartzScheduler.triggerJob(jobKey);
        return true;
    }

    //删除任务详情
    @PostMapping("quartz/deleteJobDetail")
    @ResponseBody
    public boolean deleteJobDetail(@NotNull String jobName, @NotNull String jobGroup) throws Exception {
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        List<Trigger> triggers = (List<Trigger>) quartzScheduler.getTriggersOfJob(jobKey);
        if (triggers.size() > 0) {
            return false;
        }
        return quartzScheduler.deleteJob(jobKey);
    }

    //    @SuppressWarnings("unchecked")
    private List<JobEntity> getSchedulerJobInfo() throws SchedulerException {
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        quartzScheduler = schedulerFactory.getScheduler();

        List<JobEntity> jobInfos = new ArrayList<JobEntity>();
        List<String> triggerGroupNames = quartzScheduler.getTriggerGroupNames();
        for (String triggerGroupName : triggerGroupNames) {
            Set<TriggerKey> triggerKeySet = quartzScheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(triggerGroupName));
            for (TriggerKey triggerKey : triggerKeySet) {
                Trigger t = quartzScheduler.getTrigger(triggerKey);
                JobEntity jobInfo = new JobEntity();
                if (t instanceof CronTrigger) {
                    CronTrigger trigger = (CronTrigger) t;
                    jobInfo.setCronExpr(trigger.getCronExpression());
                } else if (t instanceof SimpleTrigger) {
                    SimpleTrigger trigger = (SimpleTrigger) t;
                    jobInfo.setCronExpr(trigger.getRepeatCount() + 1 + "-" + trigger.getTimesTriggered() + "(" + trigger.getRepeatInterval() + ")");

                }
                JobKey jobKey = t.getJobKey();
                JobDetail jd = quartzScheduler.getJobDetail(jobKey);
                jobInfo.setJobName(jobKey.getName());
                jobInfo.setJobGroup(jobKey.getGroup());
                jobInfo.setTriggerName(triggerKey.getName());
                jobInfo.setTriggerGroupName(triggerKey.getGroup());
                jobInfo.setNextFireTime(t.getNextFireTime());
                jobInfo.setPreviousFireTime(t.getPreviousFireTime());
                jobInfo.setStartTime(t.getStartTime());
                jobInfo.setEndTime(t.getEndTime());
                jobInfo.setJobClass(jd.getJobClass().getCanonicalName());
                jobInfo.setDescription(t.getDescription());

                Trigger.TriggerState triggerState = quartzScheduler.getTriggerState(t.getKey());
                jobInfo.setJobStatus(triggerState.toString());// NONE无, NORMAL正常, PAUSED暂停, COMPLETE完全, ERROR错误, BLOCKED阻塞
                JobDataMap map = quartzScheduler.getJobDetail(jobKey).getJobDataMap();
//                jobInfo.setCount(Integer.parseInt((String) map.get("count")));
                if (null != map) {
                    jobInfo.setJobDataMap(map);
                } else {
                    jobInfo.setJobDataMap(new JobDataMap());
                }
                jobInfos.add(jobInfo);
            }
        }
        return jobInfos;
    }

    //    @SuppressWarnings("unchecked")
    private List<JobDetailManage> getJobDetailInfos() throws SchedulerException {
        List<JobDetailManage> jobDetailInfos = new ArrayList<JobDetailManage>();

        for (String groupName : quartzScheduler.getJobGroupNames()) {
            for (JobKey jobKey : quartzScheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
                jobDetailInfos.add(getJobDetailInfo(jobKey));
            }
        }
        return jobDetailInfos;
    }

    //    @SuppressWarnings("unchecked")
    private JobDetailManage getJobDetailInfo(JobKey jobKey) throws SchedulerException {
        JobDetail jobDetail = quartzScheduler.getJobDetail(jobKey);
        List<Trigger> triggers = (List<Trigger>) quartzScheduler.getTriggersOfJob(jobKey);

        if(jobDetail != null){
            JobDetailManage jobDetailManage = new JobDetailManage();
            jobDetailManage.setJobName(jobKey.getName());
            jobDetailManage.setJobGroup(jobKey.getGroup());
            jobDetailManage.setDescription(jobDetail.getDescription());
            jobDetailManage.setDuration(jobDetail.isDurable());
            jobDetailManage.setJobClass(jobDetail.getJobClass().getCanonicalName());
            jobDetailManage.setJobDataMap(jobDetail.getJobDataMap());
            jobDetailManage.setPersistJobDataAfterExecution(jobDetail.isPersistJobDataAfterExecution());
            jobDetailManage.setConcurrentExectionDisallowed(jobDetail.isConcurrentExectionDisallowed());
            jobDetailManage.setRequestsRecovery(jobDetail.requestsRecovery());
            jobDetailManage.setTriggerCount(triggers.size());

            return jobDetailManage;
        }
        return null;
    }
}

  

 JobDetailManage类:

package com.sky.bean;

import org.quartz.JobDataMap;

/**
 * @author sky
 */
public class JobDetailManage {
    private String jobName;
    private String jobGroup;
    private String description;
    private Boolean duration;
    private String jobClass;
    private JobDataMap jobDataMap;
    private Boolean concurrentExectionDisallowed;
    private Boolean persistJobDataAfterExecution;
    private Boolean requestsRecovery;
    private Integer triggerCount;

    //get set
}

  

JobEntity类:

package com.sky.bean;

import org.quartz.JobDataMap;

import java.util.Date;

/**
 * 调度器信息
 *
 * @author sky
 */
public class JobEntity {
    private int jobId;
    private String jobType;
    private String jobGroup;
    private String jobName;
    private String triggerName;
    private String triggerGroupName;
    private String cronExpr;
    private String description;
    private Date previousFireTime;
    private Date nextFireTime;
    private String jobStatus;
    private Date startTime;
    private Date endTime;
    private Date reStartTime;
    private String jobClass;
    private int count;
    private JobDataMap jobDataMap;

    //get set
}

  

posted @ 2017-06-07 15:41  sky丶尕少  阅读(2323)  评论(0编辑  收藏  举报