quartz定時任務動態配置詳細教程(附demo)(三)

源碼地址:https://gitee.com/seek412/quartz03.git
上一章節中介紹了spring整合quartz定時任務,但是想要修改、停止定時任務就必須重啓服務器。實際需求往往更復雜,下面介紹如何在前端頁面控制定時任務的啓動,暫停,修改定時任務的時間等

項目結構
項目結構圖

步驟1:數據庫設計

在上一章介紹了spring整合quartz,下面是配置文件

<!-- class文件對應定時任務的路徑,如果有多個定時任務就配置多個 -->
    <bean id="quartzJobA" class="com.demo.schedule.QuartzJobA"/>
    <bean id="quartzJobB" class="com.demo.schedule.QuartzJobB"/>

    <bean id="jobDetailA" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <!-- 這裏的name必須是targetObject和targetMethod -->
        <property name="targetObject" ref="quartzJobA"/>
        <property name="targetMethod" value="jobA"/>
    </bean>

    <bean id="jobDetailB" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="quartzJobB"/>
        <property name="targetMethod" value="jobB"/>
    </bean>

    <!-- 定義觸發的條件 -->
    <bean id="jobTriggerA" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <!-- 這裏的name必須是jobDetail和cronExpression -->
        <property name="jobDetail" ref="jobDetailA"/>
        <!-- 每隔5秒執行一次 -->
        <property name="cronExpression" value="0/5 * * * * ?"/>
    </bean>
    <bean id="jobTriggerB" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail" ref="jobDetailB"/>
        <property name="cronExpression" value="0/5 * * * * ?"/>
    </bean>
    <!-- 總管理類,如果將lazy-init='false',那麼容器啓動就會執行調度程序 -->
    <bean id="startQuartz" lazy-init="false" autowire="no"
          class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="jobTriggerA"/>
                <ref bean="jobTriggerB"/>
            </list>
        </property>
    </bean>

從上面的配置文件中我們可以看到,有如下字段需要我們指定:

bean id
bean class:需要執行的定時任務的路徑
targetMethod:需要執行的定時任務的方法
Expression:定時任務執行頻率

設計數據庫字段如下:

    CREATE TABLE `schedule_job` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
  `job_name` varchar(255) DEFAULT NULL COMMENT '任務名',
  `job_group` varchar(255) DEFAULT NULL COMMENT '任務組',
  `method_name` varchar(255) DEFAULT NULL COMMENT '要執行的方法',
  `bean_class` varchar(255) DEFAULT NULL COMMENT '定時任務所在的類路徑',
  `status` int(11) DEFAULT NULL COMMENT '任務狀態  0:正常  1:暫停',
  `cron_expression` varchar(255) DEFAULT NULL COMMENT '時間表達式',
  `params` varchar(255) DEFAULT NULL COMMENT '參數',
  `remark` varchar(255) DEFAULT NULL COMMENT '備註',
  `create_time` datetime DEFAULT NULL COMMENT '創建時間',
  `modify_time` datetime DEFAULT NULL COMMENT '修改時間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

步驟2:搭建ssm開發環境

2.1 引入依賴包

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.demo</groupId>
    <artifactId>quartz03</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>quartz03 Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <!-- 引入項目依賴的jar包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>

        <!-- spring jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>

        <!-- spring面向切面編程 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.2</version>
        </dependency>

        <!-- mybatis與spring整合包 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>

        <!-- mybatis逆向工程-->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.5</version>
        </dependency>

        <!-- pageHelper分頁插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.0.0</version>
        </dependency>

        <!-- 數據庫連接池druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.18</version>
        </dependency>

        <!-- 數據庫驅動包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>

        <!--servlet相關-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
        </dependency>


        <!-- 引入org.apache.commons.lang包-->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>

        <!-- quartz作業調度-->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>

        <!-- json解析 -->
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.9.13</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.7.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.7.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.7.4</version>
        </dependency>


    </dependencies>
    <build>
        <finalName>quartz03</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

2.2 添加配置文件

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <!-- 1. 配置數據庫配置文件 -->
    <bean id = "property" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:database.properties</value>
            </list>
        </property>
    </bean>
    <!-- 2. 使用druid連接數據庫 -->
    <bean id = "dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method = "close">
        <!-- 數據庫基本信息配置 -->
        <property name = "url" value = "${url}" />
        <property name = "username" value = "${username}" />
        <property name = "password" value = "${password}" />
        <property name = "driverClassName" value = "${driverClassName}" />
        <property name = "filters" value = "${filters}" />
        <!-- 最大併發連接數 -->
        <property name = "maxActive" value = "${maxActive}" />
        <!-- 初始化連接數量 -->
        <property name = "initialSize" value = "${initialSize}" />
        <!-- 配置獲取連接等待超時的時間 -->
        <property name = "maxWait" value = "${maxWait}" />
        <!-- 最小空閒連接數 -->
        <property name = "minIdle" value = "${minIdle}" />
        <!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連接,單位是毫秒 -->
        <property name = "timeBetweenEvictionRunsMillis" value ="${timeBetweenEvictionRunsMillis}" />
        <!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
        <property name = "minEvictableIdleTimeMillis" value ="${minEvictableIdleTimeMillis}" />
        <!-- 用來檢測連接是否有效sql,要求是一個查詢語句 -->
        <property name = "validationQuery" value = "${validationQuery}" />
        <!-- 建議配置爲true,不影響性能,並且保證安全性 -->
        <property name = "testWhileIdle" value = "${testWhileIdle}" />
        <!-- 申請連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能 -->
        <property name = "testOnBorrow" value = "${testOnBorrow}" />
        <!-- 歸還連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能 -->
        <property name = "testOnReturn" value = "${testOnReturn}" />
        <!-- 要啓用PSCache,必須配置大於0 -->
        <property name = "maxOpenPreparedStatements" value ="${maxOpenPreparedStatements}" />
        <!-- 打開 removeAbandoned 功能 -->
        <property name = "removeAbandoned" value = "${removeAbandoned}" />
        <!-- 1800 秒,也就是 30 分鐘 -->
        <property name = "removeAbandonedTimeout" value ="${removeAbandonedTimeout}" />
        <!-- 關閉 abanded 連接時輸出錯誤日誌 -->
        <property name = "logAbandoned" value = "${logAbandoned}" />
    </bean>

    <!-- 3. 啓用自動掃描 -->
    <context:component-scan base-package="com.demo.*">
        <!-- 排除註解爲controller的類型 -->
        <context:exclude-filter type="annotation"  expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

    <!-- 4. 配置和mybatis的整合 -->
    <bean id = "sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 指定mybatis的全局文件位置 -->
        <property name="configLocation" value="classpath:mybatis.xml"/>
        <property name="dataSource" ref="dataSource"/>
        <!-- 指定mybatis的mapper文件 -->
        <property name="mapperLocations">
            <list>
                <value>classpath:/mapper/*.xml</value>
            </list>
        </property>
    </bean>

    <!-- 5. 配置掃描器,將mybatis接口的實現加入到ioc容器中 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 掃描所有dao接口的實現,加入到 ioc容器中 -->
        <property name="basePackage" value="com.demo.dao"/>
    </bean>

    <!-- 6. 事務控制 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 控制住數據源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- 7. 開啓基於註解的事務,使用xml配置形式的事務 -->
    <aop:config>
        <!-- 切入點表達式 -->
        <aop:pointcut expression="execution(* com.demo.service..*(..))" id="txPoint"/>
        <!-- 配置事務增強 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
    </aop:config>

    <!--  8. 配置事務增強,也就是事務如何切入 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 所有的方法都是事務方法 -->
            <tx:method name="*"/>
            <!-- 以get開始的所有方法 -->
            <tx:method name="get*" read-only="true"/>
        </tx:attributes>
    </tx:advice>

    <bean id = "springContextUtils" class="com.demo.common.utils.SpringContextUtils"/>
     <!--9. Quartz定時任務動態配置 -->
    <bean id = "schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"/>
</beans>

spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.1.xsd

    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
    <!-- 1. 註解探測器 -->
    <context:component-scan base-package="com.demo.controller">
    </context:component-scan>

    <!-- 2. 配置視圖解析器,方便頁面返回-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/page/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- 3.兩個標準配置 -->
    <mvc:default-servlet-handler/>
    <mvc:annotation-driven/>

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
            </list>
        </property>
    </bean>
</beans>

mybatis.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 1. 駝峯規則命名 -->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!-- 2. 別名 -->
    <typeAliases>
        <typeAlias type="com.demo.domain.ScheduleJob" alias="ScheduleJob"/>
    </typeAliases>
    <!-- 3. 引入分頁插件 -->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"/>
    </plugins>
</configuration>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>Archetype Created Web Application</display-name>
    <!-- 1. 啓動spring容器 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 2. springmvc前端控制器,攔截所有請求 -->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.json</url-pattern>
    </servlet-mapping>

    <!-- 3. 字符編碼過濾器配置 ,字符過濾器要放在所有過濾器的前面-->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- 5. 連接池啓用Web監控統計功能start-->
    <filter>
        <filter-name>DruidWebStatFilter</filter-name>
        <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
        <init-param>
            <param-name>exclusions</param-name>
            <param-value>*. js ,*. gif ,*. jpg ,*. png ,*. css ,*. ico ,/ druid /*</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>DruidWebStatFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>DruidStatView</servlet-name>
        <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DruidStatView</servlet-name>
        <url-pattern>/druid/*</url-pattern>
    </servlet-mapping>
    <!-- 連接池啓用Web監控統計功能end-->
</web-app>

database.properties

#druid配置
url:jdbc\:mysql\://localhost\:3306/quartz03?characterEncoding\=utf8&allowMultiQueries\=true
driverClassName:com.mysql.jdbc.Driver
username:root
password:admin
filters:stat
maxActive:20
initialSize:1
maxWait:60000
minIdle:10
maxIdle:15
timeBetweenEvictionRunsMillis:60000
minEvictableIdleTimeMillis:300000
validationQuery:SELECT 'x'
testWhileIdle:true
testOnBorrow:false
testOnReturn:false
maxOpenPreparedStatements:20
removeAbandoned:true
removeAbandonedTimeout:1800
logAbandoned:true

步驟3:前端頁面

前端頁面表格使用的bootstrap table,這裏不再累述,頁面樣式如下:
index.jsp

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2017/11/25 0020
  Time: 下午 18:28
  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="fn"  uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<c:set var="basePath" value="${pageContext.request.contextPath}" />
<!DOCTYPE html>
<html>
<head>
    <title>定時任務</title>
    <link rel="stylesheet" href="${basePath}/static/bootstrap-dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="${basePath}/static/font-awesome/css/font-awesome.min.css">
    <link rel="stylesheet" href="${basePath}/static/css/bootstrap-table.min.css">
    <script src="${basePath}/static/js/jquery-2.0.3.min.js"></script>
    <script src="${basePath}/static/bootstrap-dist/js/bootstrap.min.js"></script>
    <script src="${basePath}/static/js/bootstrap-table.min.js"></script>
    <script src="${basePath}/static/js/bootstrap-table-zh-CN.js"></script>
</head>
<body>

<div id="rrapp" style="margin: 100px;">
    <div id="showList">
        <div class="grid-btn" style="height:34px;">
            <a class="btn btn-primary" onclick="update();"><i class="fa fa-pencil-square-o"></i>&nbsp;修改</a>
            <a class="btn btn-primary" onclick="pause();"><i class="fa fa-pause"></i>&nbsp;暫停</a>
            <a class="btn btn-primary" onclick="resume();"><i class="fa fa-play"></i>&nbsp;恢復</a>
            <a class="btn btn-primary" onclick="runOnce();"><i class="fa fa-arrow-circle-right"></i>&nbsp;立即執行</a>
        </div>
        <table id="table"></table>
    </div>

    <!-- 修改時間模態框 -->
    <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                    <h4 class="modal-title" id="myModalLabel">修改定時任務時間</h4>
                </div>
                <div class="modal-body">
                    <input type="text" id="modalId" style="display:none"/>
                    Cron表達式
                    <input type="text" class="form-control" id="modalCron">
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                    <button type="button" class="btn btn-primary" onclick="updateCron();">Save changes</button>
                </div>
            </div>
        </div>
    </div>

</div>

<script type="text/javascript">
    $(function () {
        //初始化表格
        initTable();
    });

    //修改按鈕
    function update() {
        //獲取選中的行
        var a = $("#table").bootstrapTable('getSelections');
        if (a.length == 0) {
            alert("請先選中需要修改的項");
            return false;
        } else if (a.length > 1) {
            alert("只能選擇一項");
            return false;
        }
        $("#modalId").val(a[0].id);
        $('#myModal').modal('toggle');
    }

    //更新定時任務時間
    function updateCron() {
        $('#myModal').modal('hide');
        var id = $("#modalId").val();
        var queryUrl = "${basePath}/scheduleJob/updateCron.do";
        $.ajax({
            type: 'POST',
            data: {
                id: id,
                cronExpression: $("#modalCron").val(),
            },
            url: queryUrl,
            success: function (result) {
                //刷新表格
                var opt = {
                    url: '${basePath}/scheduleJob/listAllJob.do'
                };
                $("#table").bootstrapTable('refresh', opt);
            }
        })
    }

    //暫停一個定時任務
    function pause() {
        var queryUrl = '${basePath}/scheduleJob/pauseJob.do';
        commonSubmit(queryUrl);
    }

    //恢復一個定時任務
    function resume() {
        var queryUrl = '${basePath}/scheduleJob/resumeJob.do';
        commonSubmit(queryUrl);
    }

    //立即執行一個定時任務
    function runOnce() {
        var queryUrl = "${basePath}/scheduleJob/runOnce.do";
        commonSubmit(queryUrl);
    }

    //暫停、恢復、立即執行提交函數
    function commonSubmit(queryUrl) {
        //獲取選中的行
        var a = $("#table").bootstrapTable('getSelections');
        if (a.length == 0) {
            alert("請先選中需要修改的項");
            return false;
        } else if (a.length > 1) {
            alert("只能選擇一項");
            return false;
        }
        var obj = a[0];
        $.ajax({
            type: 'post',
            data: {
                jobId: obj.id
            },
            url: queryUrl,
            success: function (result) {
                //刷新表格,狀態變更
                var opt = {
                    url: '${basePath}/scheduleJob/listAllJob.do'
                };
                $("#table").bootstrapTable('refresh', opt);
            }
        });
    }

    //表格詳情
    function initTable() {
        var queryUrl = '${basePath}/scheduleJob/listAllJob.do';
        $('#table').bootstrapTable({
            method: 'POST',//請求方式(*)
            contentType: "application/x-www-form-urlencoded;charset=UTF-8",//在服務端分頁時必須配置
            dataType: 'json',
            //toolbar: '#toolbar',//工具按鈕用哪個容器
            striped: true,//是否顯示行間隔色
            cache: false,//是否使用緩存,默認爲true,所以一般情況下需要設置一下這個屬性(*)
            pagination: true,//是否顯示分頁(*)、
            onlyInfoPagination: false,//設置爲true時只顯示總數據,而不顯示分頁按鈕
            showPaginationSwitch: false,
            sortable: true,//是否啓用排序
            sortOrder: "asc",//排序方式
            sidePagination: "server",//分頁方式:client客戶端分頁,server服務端分頁(*)
            pageNumber: 1,//初始化加載第一頁,默認第一頁,並記錄
            pageSize: 10,//每頁的記錄行數(*)
            pageList: [10, 25, 50, 100],//可供選擇的每頁的行數(*)
            url: queryUrl,//請求後臺的URL(*)
            search: false,//是否顯示錶格搜索
            strictSearch: true,
            showColumns: false,//是否顯示所有的列(選擇顯示的列)
            showRefresh: false,//是否顯示刷新按鈕
            minimumCountColumns: 1,//最少允許的列數
            clickToSelect: true,//是否啓用點擊選中行
            //height: 500,                      //行高,如果沒有設置height屬性,表格自動根據記錄條數覺得表格高度
            uniqueId: "ID",//每一行的唯一標識,一般爲主鍵列
            showToggle: false, //是否顯示詳細視圖和列表視圖的切換按鈕
            cardView: false,//是否顯示詳細視圖
            detailView: false,//是否顯示父子表
            paginationDetailHAlign: "left",//設置頁面條數信息位置,默認在左邊
            showExport: false,                     //是否顯示導出
            exportDataType: "selected",              //basic', 'all', 'selected'.
            //獲取查詢參數
            queryParams: function queryParams(params) {
                //這裏的鍵的名字和控制器的變量名必須一致,這邊改動,控制器也需要改成一樣的
                var param = {
                    pageSize: params.limit,                       //頁面大小
                    pageNumber: (params.offset / params.limit) + 1,   //頁碼
                    menuName: $("#menuNameQuery").val(), //菜單名稱
                    parentName: $("#parentNameQuery").val(),//上級菜單名稱
                };
                return param;
            },
            columns: [
                {
                    field: 'Number',
                    title: '',
                    align: 'center',
                    width: 20,
                    formatter: function (value, row, index) {
                        return index + 1;
                    }
                },
                {
                    checkbox: true,
                    visible: true                  //是否顯示覆選框
                }, {
                    field: 'id',
                    title: '任務ID',
                    width: 50,
                    align: 'center'
                }, {
                    field: 'jobName',
                    title: 'JobName',
                    width: 150,
                    align: 'center'
                }, {
                    field: 'jobGroup',
                    title: 'JobGroup',
                    width: 50,
                    align: 'center'
                }, {
                    field: 'beanClass',
                    title: 'BeanClass',
                    align: 'center'
                }, {
                    field: 'methodName',
                    title: 'MethodName',
                    width: 100,
                    align: 'center'
                }, {
                    field: 'params',
                    title: '參數',
                    width: 100,
                    align: 'center'
                }, {
                    field: 'cronExpression',
                    title: 'cron表達式',
                    width: 100,
                    align: 'center'
                }, {
                    field: 'status',
                    title: '狀態',
                    width: 50,
                    align: 'center',
                    formatter: function (value, row, index) {
                        if (value == 0) {
                            return "<a href='javascript:void(0);' class='btn btn-primary btn-xs'>正常</a>";
                        }
                        if (value == 1) {
                            return "<a href='javascript:void(0);' class='btn btn-danger btn-xs'>暫停</a>";
                        }
                    }
                }, {
                    field: 'remark',
                    title: '備註',
                    width: 100,
                    align: 'center'
                }],
        });
    }
</script>
</body>
</html>

步驟4:定時任務的啓動、暫停、時間修改、立即執行

在數據庫中我們有設計字段status表示定時任務的狀態,0表示正常狀態,1表示暫停狀態
啓動服務器時需要啓動status爲1的定時任務

4.1 項目啓動時啓動定時任務

在service在中添加初始化方法,在方法前添加@PostConstruct註解。在方法裏面添加調用定時任務的方法

被@PostConstruct修飾的方法會在服務器加載Servlet的時候運行,並且只會被服務器調用一次,類似於Serclet的init()方法

4.2 定時任務的時間修改、暫停、立即執行

定時任務的修改、暫停主要是調用quartz內置方法pauseJob()、resumeJob()、triggerJob()等方法

 //暫停一個job
 JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
 scheduler.pauseJob(jobKey);
// 恢復一個定時任務
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.resumeJob(jobKey);
// 立即執行一個定時任務
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.triggerJob(jobKey);
// 更新時間表達式
TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
CronScheduleBuilder scheduleBuilder =           
            CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
trigger = trigger.getTriggerBuilder()
        .withIdentity(triggerKey)
        .build();
scheduler.rescheduleJob(triggerKey,trigger);

ScheduleJobServiceImpl

package com.demo.service.impl;

import com.demo.common.result.BootstrapTableResult;
import com.demo.common.result.Constant;
import com.demo.dao.ScheduleJobMapper;
import com.demo.domain.ScheduleJob;
import com.demo.schedule.QuartzJobFactory;
import com.demo.service.ScheduleJobService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;

/**
 * @author Administrator
 * @date 2017-11-21 上午 9:36
 */
@Service("scheduleJobService")
public class ScheduleJobServiceImpl implements ScheduleJobService {
    private Logger log = LoggerFactory.getLogger(ScheduleJobServiceImpl.class);

    @Resource
    private ScheduleJobMapper scheduleJobMapper;
    @Resource
    private Scheduler scheduler;

    public Scheduler getScheduler() {
        return scheduler;
    }

    public void setScheduler(Scheduler scheduler) {
        this.scheduler = scheduler;
    }

    /**
     * 項目啓動時初始化定時器
     */
    @PostConstruct
    public void init() {
        //獲取所有的定時任務
        List<ScheduleJob> scheduleJobList = scheduleJobMapper.listAllJob();
        if (scheduleJobList.size() != 0) {
            for (ScheduleJob scheduleJob : scheduleJobList) {
                    addJob(scheduleJob);
            }
        }
    }

    /**
     * 添加任務
     * @param job
     */
    private void addJob(ScheduleJob job) {
        try {
            log.info("初始化");
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

            //不存在,則創建
            if (null == trigger) {
                Class clazz = QuartzJobFactory.class;
                JobDetail jobDetail = JobBuilder.
                        newJob(clazz).
                        withIdentity(job.getJobName(), job.getJobGroup()).
                        build();
                jobDetail.getJobDataMap().put("scheduleJob", job);

                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

                //withIdentity中寫jobName和groupName
                trigger = TriggerBuilder.
                        newTrigger().
                        withIdentity(job.getJobName(), job.getJobGroup())
                        .withSchedule(scheduleBuilder)
                        .build();
                scheduler.scheduleJob(jobDetail, trigger);
                //如果定時任務是暫停狀態
                if(job.getStatus() == Constant.STATUS_NOT_RUNNING){
                    pauseJob(job.getId());
                }
            } else {
                // Trigger已存在,那麼更新相應的定時設置
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

                // 按新的cronExpression表達式重新構建trigger
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

                // 按新的trigger重新設置job執行
                scheduler.rescheduleJob(triggerKey, trigger);
            }
        } catch (Exception e) {
            log.error("添加任務失敗", e);
        }
    }

    /**
     * 查詢所有的定時任務
     * @return BootstrapTableResult
     */
    @Override
    public BootstrapTableResult listAllJob(int pageSize, int pageNumber) {
        PageHelper.startPage(pageNumber, pageSize);
        List<ScheduleJob> scheduleJobList = scheduleJobMapper.listAllJob();
        PageInfo pageInfo = new PageInfo(scheduleJobList, Constant.PAGENUMBER);
        int total = (int) pageInfo.getTotal();
        BootstrapTableResult bootstrapTableResult = new BootstrapTableResult(total, scheduleJobList);
        return bootstrapTableResult;
    }

    /**
     * 暫停定時任務
     * @param jobId
     */
    @Override
    public void pauseJob(int jobId) {
        //修改定時任務狀態
        ScheduleJob scheduleJob = getScheduleJobByPrimaryKey(jobId);
        scheduleJob.setId(jobId);
        scheduleJob.setStatus(Constant.STATUS_NOT_RUNNING);
        updateJobStatusById(scheduleJob);
        try {
            //暫停一個job
            JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
            scheduler.pauseJob(jobKey);
        }catch (Exception e){
            log.error("CatchException:暫停任務失敗",e);
        }
    }

    /**
     * 恢復一個定時任務
     * @param jobId
     */
    @Override
    public void resumeJob(int jobId) {
        //修改定時任務狀態
        ScheduleJob scheduleJob = getScheduleJobByPrimaryKey(jobId);
        scheduleJob.setStatus(Constant.STATUS_RUNNING);
        updateJobStatusById(scheduleJob);
        try{
            //恢復一個定時任務
            JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
            scheduler.resumeJob(jobKey);
        }catch (Exception e){
            log.error("CatchException:恢復定時任務失敗",e);
        }
    }

    /**
     * 立即執行一個定時任務
     * @param jobId
     */
    @Override
    public void runOnce(int jobId) {
        try{
            ScheduleJob scheduleJob = getScheduleJobByPrimaryKey(jobId);
            JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
            scheduler.triggerJob(jobKey);
        }catch (Exception e){
            log.error("CatchException:恢復定時任務失敗",e);
        }
    }

    /**
     * 更新時間表達式
     * @param id
     * @param cronExpression
     */
    @Override
    public void updateCron(int id, String cronExpression) {
        ScheduleJob scheduleJob = getScheduleJobByPrimaryKey(id);
        scheduleJob.setCronExpression(cronExpression);
        updateJobCronExpressionById(scheduleJob);
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            scheduler.rescheduleJob(triggerKey,trigger);
        }catch(Exception e){
            log.error("CatchException:更新時間表達式失敗",e);
        }

    }

    /**
     * 修改定時任務狀態
     * @param scheduleJob
     */
    private void updateJobStatusById(ScheduleJob scheduleJob){
        scheduleJobMapper.updateJobStatusById(scheduleJob);
    }

    /**
     * 修改定時任務時間
     */
    private void updateJobCronExpressionById(ScheduleJob scheduleJob){
        scheduleJobMapper.updateJobCronExpressionById(scheduleJob);
    }

    /**
     * 通過主鍵id查找定時任務
     * @param id
     * @return ScheduleJob
     */
    private ScheduleJob getScheduleJobByPrimaryKey(int id){
        return scheduleJobMapper.getScheduleJobByPrimaryKey(id);
    }


}

QuartzJobFactory.java

package com.demo.schedule;

import com.demo.common.utils.TaskUtils;
import com.demo.domain.ScheduleJob;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author admin
 * @date 2017-11-25 下午 21:49
 */
public class QuartzJobFactory implements Job {
    public Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("定時任務運行中...");
        ScheduleJob scheduleJob = (ScheduleJob) jobExecutionContext.getMergedJobDataMap().get("scheduleJob");
        TaskUtils.invokeMethod(scheduleJob);
    }
}

執行計劃任務的代碼就在TaskUtils.invokMethod(scheduleJob)裏面,通過scheduleJob的beanClass來獲得需要執行的類,通過methodName來確定執行哪個方法
定時任務啓動後,可以直接修改啓動、暫停狀態,但是重啓服務器時並不會記錄當前狀態,建議先將修改後的狀態保存到數據庫status字段中

TaskUtils.java

package com.demo.common.utils;
import com.demo.domain.ScheduleJob;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


/**
 * @author admin
 * @date 2017-11-21 下午 16:07
 */
public class TaskUtils {
    public static Logger log = LoggerFactory.getLogger(TaskUtils.class);
    public static void invokeMethod(ScheduleJob scheduleJob) {
        Object object = null;
        Class clazz = null;
        if (StringUtils.isNotBlank(scheduleJob.getBeanClass())) {
            try {
                clazz = Class.forName(scheduleJob.getBeanClass());
                object = clazz.newInstance();
            } catch (Exception e) {
                log.error("CatchException:",e);
            }
        }
        if (object == null) {
            log.error("任務名稱 = [" + scheduleJob.getJobName() + "]---------------未啓動成功,請檢查是否配置正確!!!");
            System.out.println("任務名稱 = [" + scheduleJob.getJobName() + "]---------------未啓動成功,請檢查是否配置正確!!!");
            return;
        }
        clazz = object.getClass();
        Method method = null;
        try {
            method = clazz.getDeclaredMethod(scheduleJob.getMethodName());
        } catch (NoSuchMethodException e) {
            log.error("任務名稱 = [" + scheduleJob.getJobName() + "]---------------未啓動成功,方法名設置錯誤!!!");
            System.out.println("任務名稱 = [" + scheduleJob.getJobName() + "]---------------未啓動成功,方法名設置錯誤!!!");
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        if (method != null) {
            try {
                method.invoke(object);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        log.info("任務名稱 = [" + scheduleJob.getJobName() + "]----------啓動成功");
    }
}

SpringContextUtil.java

package com.demo.common.utils;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 獲取spring容器,以訪問容器中定義的其他bean
 * @author Administrator
 * @date 2017-11-21 下午 12:39
 */
@Component
public class SpringContextUtils implements ApplicationContextAware {
    /**
     * Spring應用上下文環境
     */
    public static ApplicationContext applicationContext;

    /**
     * 實現ApplicationContextAware接口的回調方法,設置上下文環境
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextUtils.applicationContext = applicationContext;
    }

    /**
     * 獲取對象 這裏重寫了bean方法,起主要作用
     * @param name
     * @return Object 一個以所給名字註冊的bean的實例
     * @throws BeansException
     */
    public static <T> T  getBean(String name) throws BeansException {
        return (T) applicationContext.getBean(name);
    }

    /**
     * 如果BeanFactory包含一個與所給名稱匹配的bean定義,則返回true
     * @param name
     * @return boolean
     */
    public static boolean containsBean(String name) {
        return applicationContext.containsBean(name);
    }

    /**
     * 判斷以給定名字註冊的bean定義是一個singleton還是一個prototype。
     * 如果與給定名字相應的bean定義沒有被找到,將會拋出一個異常(NoSuchBeanDefinitionException)
     * @param name
     * @return boolean
     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
     */
    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
        return applicationContext.isSingleton(name);
    }

    /**
     * @param name
     * @return Class 註冊對象的類型
     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
     *
     */
    public static Class<? extends Object> getType(String name) throws NoSuchBeanDefinitionException {
        return applicationContext.getType(name);
    }

    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
        return applicationContext.getAliases(name);
    }

}

4.3 需要執行的定時任務

TaskTest1.java

package com.demo.schedule;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;
import java.util.Map;

/**
 * @author admin
 * @date 2017-11-25 下午 20:14
 */
@Component
public class TaskTest1 {
    public static final Logger LOGGER = LoggerFactory.getLogger(TaskTest1.class);

    public void run1(){
        System.out.println("執行方法1");
    }

    public void run2(){
        System.out.println("執行方法2");
    }

    public void run3(){
        System.out.println("執行方法3");
    }

    public void run4(){
        System.out.println("執行方法4");
    }
}

4.4 項目中涉及到的其他文件

Constant.java

/**
 * 常量類
 * @author admin
 * @date 2017-11-25 19:06
 */
public class Constant {
    /**
     * 分頁條顯示頁數
     */
    public static final int PAGENUMBER = 5;
    /**
     * 定時任務啓動狀態
     */
    public static final int STATUS_RUNNING = 0;
    /**
     * 定時任務暫停狀態
     */
    public static final int STATUS_NOT_RUNNING = 1;
}

BootstrapTableResult.java

/**
 * bootstrapTable所需的結果集
 * @author admin
 * @date 2017-11-25 18:59
 */
 public class BootstrapTableResult {
    /**
     * 總記錄數
     */
    private Integer total;
    /**
     * 結果集的list集合
     */
    private List rows;
    省略get/set...
}

BaseResult.java

/**
 * 統一返回結果類
 * @author Administrator
 * @date 2017-11-25 下午 20:07
 */
public class BaseResult {
    /**
     * 狀態碼:1成功,其他爲失敗
     */
    private int code;

    /**
     * 成功爲success,其他爲失敗原因
     */
    private String message;

    /**
     * 數據結果集
     */
    public Object data;
    省略get/set

ScheduleJob實體類

/**
 * 定時任務實體類
 * @author admin
 * @date 2017-11-25 下午 19:06
 */
public class ScheduleJob {
    /**
     * 主鍵id
     */
    private Integer id;
    /**
     * 任務名
     */
    private String jobName;
    /**
     * 任務組
     */
    private String jobGroup;
    /**
     * 要執行的方法的名稱
     */
    private String methodName;
    /**
     * 要執行的方法所在的class路徑
     */
    private String beanClass;
    /**
     * 定時任務狀態,0表示正常,1表示停止
     */
    private Integer status;
    /**
     * 時間表達式
     */
    private String cronExpression;
    /**
     * 參數
     */
    private String params;
    /**
     * 備註
     */
    private String remark;
    /**
     * 創建時間
     */
    private Date createTime;
    /**
     * 修改時間
     */
    private Date modifyTime;
    省略get/set
}

Controller層:ScheduleJobController.java

package com.demo.controller;

import com.demo.common.result.BaseResult;
import com.demo.common.result.BootstrapTableResult;
import com.demo.service.ScheduleJobService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;

/**
 * 定時任務控制層
 * @author admin
 * @date 2017-11-25 18:49
 */

@Controller
@RequestMapping(value = "/scheduleJob")
public class ScheduleJobController {
    public static Logger log = LoggerFactory.getLogger(ScheduleJobController.class);

    @Resource
    private ScheduleJobService scheduleJobService;

    /**
     * 查詢所有的定時任務,用於頁面加載時顯示錶格數據
     * @param pageSize 每頁顯示數量
     * @param pageNumber 頁數
     * @return BootstrapTableResult
     */
    @RequestMapping(value = "/listAllJob", method = RequestMethod.POST)
    @ResponseBody
    public BootstrapTableResult listAllJob(int pageSize, int pageNumber) {
        BootstrapTableResult bootstrapTableResult = scheduleJobService.listAllJob(pageSize, pageNumber);
        return bootstrapTableResult;
    }

    /**
     * 暫停定時任務
     * @param jobId
     * @return BaseResult
     */
    @RequestMapping(value = "/pauseJob", method = RequestMethod.POST)
    @ResponseBody
    public BaseResult pauseJob(int jobId) {
        scheduleJobService.pauseJob(jobId);
        return new BaseResult(1, "success", "定時任務暫停成功");
    }

    /**
     * 恢復定時任務
     * @param jobId
     * @return BaseResult
     */
    @RequestMapping(value="/resumeJob",method = RequestMethod.POST)
    @ResponseBody
    public BaseResult resumeJob(int jobId){
        scheduleJobService.resumeJob(jobId);
        return new BaseResult(1, "success", "定時任務恢復成功");
    }

    /**
     * 立即執行定時任務
     * @param jobId
     * @return BaseResult
     */
    @RequestMapping(value = "/runOnce",method = RequestMethod.POST)
    @ResponseBody
    public BaseResult runOnce(int jobId){
        scheduleJobService.runOnce(jobId);
        return new BaseResult(1, "success", "立即執行定時任務成功");
    }

    /**
     * 更新時間表達式
     * @param id
     * @param cronExpression
     * @return BaseResult
     */
    @RequestMapping(value = "/updateCron",method = RequestMethod.POST)
    @ResponseBody
    public BaseResult updateCron(int id,String cronExpression){
        scheduleJobService.updateCron(id,cronExpression);
        return new BaseResult(1, "success", "更新時間表達式成功");
    }
}

dao層:ScheduleJobMapper.java

package com.demo.dao;
import com.demo.domain.ScheduleJob;
import java.util.List;
/**
 * 定時任務
 * @author admin
 * @date 2017-11-20 下午 15:52
 */
public interface ScheduleJobMapper {
    /**
     * 查詢所有的定時任務
     * @return List<ScheduleJob>
     */
    List<ScheduleJob> listAllJob();

    /**
     * 更新定時任務狀態
     * @param scheduleJob
     */
    void updateJobStatusById(ScheduleJob scheduleJob);

    /**
     * 根據主鍵查詢定時任務
     * @param id
     * @return ScheduleJob
     */
    ScheduleJob getScheduleJobByPrimaryKey(int id);

    /**
     * 更新時間表達式
     * @param scheduleJob
     */
    void updateJobCronExpressionById(ScheduleJob scheduleJob);
}

dao實現層:ScheduleJobMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.demo.dao.ScheduleJobMapper">
  <resultMap id="BaseResultMap" type="com.demo.domain.ScheduleJob">
    <id column="id" property="id" />
    <result column="job_name" property="jobName" />
    <result column="job_group" property="jobGroup" />
    <result column="method_name" property="methodName" />
    <result column="bean_class" property="beanClass" />
    <result column="status" property="status" />
    <result column="cron_expression" property="cronExpression" />
    <result column="params" property="params" />
    <result column="remark" property="remark" />
    <result column="create_time" property="createTime" />
    <result column="modify_time" property="modifyTime" />
  </resultMap>
  <sql id="Base_Column_List">
    id, job_name, job_group, method_name, bean_class, status, cron_expression, params, 
    remark, create_time, modify_time
  </sql>
    <!-- 查詢所有的定時任務 -->
    <select id="listAllJob" resultMap="BaseResultMap">
        select <include refid="Base_Column_List" /> from schedule_job
    </select>
    <!-- 更新定時任務狀態 -->
    <update id="updateJobStatusById" parameterType="ScheduleJob">
        update schedule_job SET status = #{status} where id = #{id}
    </update>
    <!-- 根據主鍵查詢定時任務 -->
    <select id = "getScheduleJobByPrimaryKey" resultMap="BaseResultMap">
        SELECT * from schedule_job WHERE id = #{id}
    </select>
    <!-- 修改定時任務時間表達式 -->
    <update id="updateJobCronExpressionById" parameterType="ScheduleJob">
        UPDATE schedule_job SET cron_expression = #{cronExpression} where id = #{id}
    </update>
</mapper>

service層:ScheduleJobService.java

package com.demo.service;

import com.demo.common.result.BootstrapTableResult;
import com.demo.dao.ScheduleJobMapper;
import org.quartz.Scheduler;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author admin
 * @date 2017-11-25 18:51
 */

public interface ScheduleJobService {
    /**
     * 查詢所有的定時任務
     * @param pageSize
     * @param pageNumber
     * @return BootstrapTableResult
     */
    BootstrapTableResult listAllJob(int pageSize, int pageNumber);

    /**
     * 暫停定時任務
     * @param jobId
     */
    void pauseJob(int jobId);

    /**
     * 恢復一個定時任務
     * @param jobId
     */
    void resumeJob(int jobId);

    /**
     * 立即執行一個定時任務
     * @param jobId
     */
    void runOnce(int jobId);

    /**
     * 更新時間表達式
     * @param id
     * @param cronExpression
     */
    void updateCron(int id, String cronExpression);
}

步驟5. 測試

在數據庫中添加以下數據
數據庫數據

第一條每5秒執行一次,第二條數據每秒執行一次,第三條和第四條數據啓動時不執行
啓動服務器,控制檯輸出如下結果
這裏寫圖片描述

修改定時任務1的時間,設置爲5秒,查看控制檯,可以看到定時任務1和定時任務2都是每5秒執行一次
修改定時任務時間
結果2

暫定、恢復、立即執行這裏就不一一測試了,有需要的自行測試(注:立即執行只會執行一次)

源碼下載地址:https://gitee.com/seek412/quartz03.git

上一篇:spring整合quartz定時任務(附demo)(二)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章