Spring是一个很优秀的框架,它无缝的集成了Quartz,简单方便的让企业级应用更好的使用Quartz进行任务的调度。下面就对Spring集成Quartz,springmvc,mybatis,mysql进行简单的介绍和示例讲解
第一步:导入相关的依赖
分别是spring相关的、mybatis、mysql、slf4j、quartz等依赖
<dependencies>
<!-- 添加Spring依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring单元测试依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<!-- spring webmvc相关jar -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- cglib asm 相关jar包 -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.2</version>
</dependency>
<!-- aspectj相关jar包 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.1</version>
</dependency>
<!-- quartz jar -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<!-- mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- alibaba data source 相关jar包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>0.2.23</version>
</dependency>
<!-- alibaba fastjson 格式化对 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.1.41</version>
</dependency>
<!-- logback start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.logback-extensions</groupId>
<artifactId>logback-ext-spring</artifactId>
<version>0.1.1</version>
</dependency>
<!--mybatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- mybatis/spring包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.0</version>
</dependency>
<!-- 添加servlet3.0核心包 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.2-b01</version>
</dependency>
<!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--单元测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
第二步:相关的配置文件
applicationContext.xml
引入数据库相关的配置文件以及配置扫描包路径,mybatis和quartz相关的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- 1.配置jdbc文件 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:jdbc.properties"/>
</bean>
<!-- 2.扫描的包路径,这里不扫描被@Controller注解的类 --><!--使用<context:component-scan/> 可以不在配置<context:annotation-config/> -->
<context:component-scan base-package="com.test">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<context:annotation-config></context:annotation-config>
<import resource="classpath:spring-mybatis.xml" />
<bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" >
<property name="dataSource" ref ="dataSource" />
<property name="applicationContextSchedulerContextKey" value="applicationContextKey"/>
<property name="configLocation" value="classpath:quartz.properties"/>
</bean>
</beans>
jdbc.properties
jdbc_driverClassName =com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/quartz_test?useUnicode=true&characterEncoding=utf8
jdbc_username=root
jdbc_password=123456
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 尽量别用绝对路径,如果带参数不同容器路径解释可能不同,以下配置参数在pom.xml里 -->
<property name="log.root.level" value="${log.root.level}" /> <!-- 日志级别 -->
<property name="log.other.level" value="${log.other.level}" /> <!-- 其他日志级别 -->
<property name="log.base" value="${log.base}" /> <!-- 日志路径,这里是相对路径,web项目eclipse下会输出到eclipse的安装目录下,如果部署到linux上的tomcat下,会输出到tomcat/bin目录 下 -->
<property name="log.moduleName" value="${log.moduleName}" /> <!-- 模块名称, 影响日志配置名,日志文件名 -->
<property name="log.max.size" value="100MB" /> <!-- 日志文件大小,超过这个大小将被压缩 -->
<!--控制台输出 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level[%thread]%logger{56}.%method\(\):%L -%msg%n</Pattern>
</encoder>
</appender>
<!-- 用来保存输出所有级别的日志 -->
<appender name="file.all" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${log.base}/${log.moduleName}.log</File><!-- 设置日志不超过${log.max.size}时的保存路径,注意如果
是web项目会保存到Tomcat的bin目录 下 -->
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.base}/archive/${log.moduleName}_all_%d{yyyy-MM-dd}.%i.log.zip
</FileNamePattern>
<!-- 文件输出日志 (文件大小策略进行文件输出,超过指定大小对文件备份) -->
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${log.max.size}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 日志输出的文件的格式 -->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level[%thread]%logger{56}.%method\(\):%L -%msg%n</pattern>
</layout>
</appender>
<!-- 这也是用来保存输出所有级别的日志 -->
<appender name="file.all.other" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${log.base}/${log.moduleName}_other.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.base}/archive/${log.moduleName}_other_%d{yyyy-MM-dd}.%i.log.zip
</FileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${log.max.size}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{56}.%method\(\):%L -%msg%n</pattern>
</layout>
</appender>
<!-- 只用保存输出error级别的日志 -->
<appender name="file.error"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${log.base}/${log.moduleName}_err.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.base}/archive/${log.moduleName}_err_%d{yyyy-MM-dd}.%i.log.zip
</FileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${log.max.size}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{56}.%method\(\):%L - %msg%n</pattern>
</layout>
<!-- 下面为配置只输出error级别的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<!-- 添加附加的appender,最多只能添加一个 -->
<appender name="file.async" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>256</queueSize>
<includeCallerData>true</includeCallerData>
<appender-ref ref="file.all" />
</appender>
<appender name="file.async.other" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>256</queueSize>
<includeCallerData>true</includeCallerData>
<appender-ref ref="file.all.other" />
</appender>
<!-- 为某个包下的所有类的指定Appender 这里也可以指定类名称例如:com.aa.bb.ClassName -->
<logger name="com.lin" additivity="false">
<level value="${log.root.level}" />
<appender-ref ref="stdout" />
<appender-ref ref="file.async" /><!-- 即com.lin包下级别为 ${log.root.level}的才会使用file.async来打印 -->
<appender-ref ref="file.error" />
</logger>
<!-- root将级别为${log.root.level}及大于${log.root.level}的日志信息交给已经配置好的名为“Console”的appender处理,“Console”appender将信息打印到Console,其它同理 -->
<root level="${log.root.level}">
<appender-ref ref="stdout" /> <!-- 标识这个appender将会添加到这个logger -->
<appender-ref ref="file.async.other" />
<appender-ref ref="file.error" />
</root>
</configuration>
quartz.properties
相关的配置详情参见Quartz的配置文件quartz.properties详解 - Rozdy - 博客园
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName: quartzScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 2
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
#============================================================================
# Configure JobStore
#============================================================================
#default config
#org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
#\u6301\u4e45\u5316\u914d\u7f6e
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties:true
#============================================================================
#havent cluster spring
#============================================================================
org.quartz.jobStore.isClustered = false
#\u6570\u636e\u5e93\u8868\u524d\u7f00
org.quartz.jobStore.tablePrefix:qrtz_
#org.quartz.jobStore.dataSource:qzDS
#============================================================================
# Configure Datasources
#============================================================================
#JDBC\u9a71\u52a8 Sping\u53bb\u7ba1\u7406dataSource \uff0c\u8fd9\u91cc\u4e0d\u5728\u914d\u7f6e\u6570\u636e\u6e90\u4fe1\u606f
#org.quartz.dataSource.qzDS.driver:com.mysql.jdbc.Driver
#org.quartz.dataSource.qzDS.URL:jdbc:mysql://localhost:3306/quartz_test
#org.quartz.dataSource.qzDS.user:root
#org.quartz.dataSource.qzDS.password:root
#org.quartz.dataSource.qzDS.maxConnection:10
spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
default-lazy-init="true">
<!-- AOP动态代理 true 表示使用Cglib动态代理,是否需要引入Cglib的jar包-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<context:annotation-config></context:annotation-config>
<!-- 扫描controller(controller层注入) -->
<context:component-scan base-package="com.test.controller" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<mvc:annotation-driven />
<!-- 内容协商管理器 -->
<!--1、首先检查路径扩展名(如my.pdf);2、其次检查Parameter(如my?format=pdf);3、检查Accept Header-->
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<!-- 扩展名至mimeType的映射,即 /user.json => application/json -->
<property name="favorPathExtension" value="true"/>
<!-- 用于开启 /userinfo/123?format=json 的支持 -->
<property name="favorParameter" value="true"/>
<property name="parameterName" value="format"/>
<!-- 是否忽略Accept Header -->
<property name="ignoreAcceptHeader" value="false"/>
<property name="mediaTypes"> <!--扩展名到MIME的映射;favorPathExtension, favorParameter是true时起作用 -->
<value>
json=application/json
xml=application/xml
html=text/html
</value>
</property>
<!-- 默认的content type -->
<property name="defaultContentType" value="text/html"/>
</bean>
<!-- 当在web.xml 中 DispatcherServlet使用 <url-pattern>/</url-pattern> 映射时,能映射静态资源 -->
<mvc:default-servlet-handler />
<!-- 静态资源映射 -->
<mvc:resources mapping="/static/**" location="/WEB-INF/static/"/>
<!-- 对模型视图添加前后缀
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/>
-->
<!-- 默认的视图解析器 在上边的解析错误时使用 (默认使用html)- -->
<bean id="defaultViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:order="2">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="contentType" value="text/html" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
spring-mybatis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
default-lazy-init="true">
<!-- AOP动态代理 true 表示使用Cglib动态代理,是否需要引入Cglib的jar包-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<context:annotation-config></context:annotation-config>
<!-- 扫描controller(controller层注入) -->
<context:component-scan base-package="com.test.controller" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<mvc:annotation-driven />
<!-- 内容协商管理器 -->
<!--1、首先检查路径扩展名(如my.pdf);2、其次检查Parameter(如my?format=pdf);3、检查Accept Header-->
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<!-- 扩展名至mimeType的映射,即 /user.json => application/json -->
<property name="favorPathExtension" value="true"/>
<!-- 用于开启 /userinfo/123?format=json 的支持 -->
<property name="favorParameter" value="true"/>
<property name="parameterName" value="format"/>
<!-- 是否忽略Accept Header -->
<property name="ignoreAcceptHeader" value="false"/>
<property name="mediaTypes"> <!--扩展名到MIME的映射;favorPathExtension, favorParameter是true时起作用 -->
<value>
json=application/json
xml=application/xml
html=text/html
</value>
</property>
<!-- 默认的content type -->
<property name="defaultContentType" value="text/html"/>
</bean>
<!-- 当在web.xml 中 DispatcherServlet使用 <url-pattern>/</url-pattern> 映射时,能映射静态资源 -->
<mvc:default-servlet-handler />
<!-- 静态资源映射 -->
<mvc:resources mapping="/static/**" location="/WEB-INF/static/"/>
<!-- 对模型视图添加前后缀
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/>
-->
<!-- 默认的视图解析器 在上边的解析错误时使用 (默认使用html)- -->
<bean id="defaultViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:order="2">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="contentType" value="text/html" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
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" 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_3_0.xsd" id="WebApp_ID" metadata-complete="true" version="3.0">
<display-name>SSM-DEMO</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<filter>
<filter-name>SpringEncodingFilter</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>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SpringEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.test.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
<context-param>
<param-name>logbackConfigLocation</param-name>
<param-value>classpath:logback.xml</param-value>
</context-param>
<listener>
<listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcherServlet</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>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
quartz_test.sql数据库文件
这个文件可以从quartz开源项目中下载,这里直接复制即可
/*
Navicat MySQL Data Transfer
Source Server : 本地
Source Server Version : 50723
Source Host : localhost:3306
Source Database : quartz_test
Target Server Type : MYSQL
Target Server Version : 50723
File Encoding : 65001
Date: 2018-11-01 16:30:21
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `qrtz_blob_triggers`
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_blob_triggers`;
CREATE TABLE `qrtz_blob_triggers` (
`sched_name` varchar(120) NOT NULL,
`trigger_name` varchar(80) NOT NULL,
`trigger_group` varchar(80) NOT NULL,
`blob_data` blob,
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of qrtz_blob_triggers
-- ----------------------------
-- ----------------------------
-- Table structure for `qrtz_calendars`
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_calendars`;
CREATE TABLE `qrtz_calendars` (
`sched_name` varchar(120) NOT NULL,
`calendar_name` varchar(80) NOT NULL,
`calendar` blob NOT NULL,
PRIMARY KEY (`calendar_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of qrtz_calendars
-- ----------------------------
-- ----------------------------
-- Table structure for `qrtz_cron_triggers`
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_cron_triggers`;
CREATE TABLE `qrtz_cron_triggers` (
`sched_name` varchar(120) NOT NULL,
`trigger_name` varchar(80) NOT NULL,
`trigger_group` varchar(80) NOT NULL,
`cron_expression` varchar(120) NOT NULL,
`time_zone_id` varchar(80) DEFAULT NULL,
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of qrtz_cron_triggers
-- ----------------------------
INSERT INTO `qrtz_cron_triggers` VALUES ('quartzScheduler', 'hw_tigger', 'hw_tigger_group', '0/5 * * * * ?', 'Asia/Shanghai');
INSERT INTO `qrtz_cron_triggers` VALUES ('quartzScheduler', 'hw_tigger1', 'hw_tigger_group1', '0/5 * * * * ?', 'Asia/Shanghai');
-- ----------------------------
-- Table structure for `qrtz_fired_triggers`
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_fired_triggers`;
CREATE TABLE `qrtz_fired_triggers` (
`sched_name` varchar(120) NOT NULL,
`entry_id` varchar(95) NOT NULL,
`trigger_name` varchar(80) NOT NULL,
`trigger_group` varchar(80) NOT NULL,
`instance_name` varchar(80) NOT NULL,
`fired_time` bigint(20) NOT NULL,
`sched_time` bigint(20) NOT NULL,
`priority` int(11) NOT NULL,
`state` varchar(16) NOT NULL,
`job_name` varchar(80) DEFAULT NULL,
`job_group` varchar(80) DEFAULT NULL,
`is_nonconcurrent` int(11) DEFAULT NULL,
`requests_recovery` int(11) DEFAULT NULL,
PRIMARY KEY (`sched_name`,`entry_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of qrtz_fired_triggers
-- ----------------------------
-- ----------------------------
-- Table structure for `qrtz_job_details`
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_job_details`;
CREATE TABLE `qrtz_job_details` (
`sched_name` varchar(120) NOT NULL,
`job_name` varchar(80) NOT NULL,
`job_group` varchar(80) NOT NULL,
`description` varchar(120) DEFAULT NULL,
`job_class_name` varchar(128) NOT NULL,
`is_durable` int(11) NOT NULL,
`is_nonconcurrent` int(11) NOT NULL,
`is_update_data` int(11) NOT NULL,
`requests_recovery` int(11) NOT NULL,
`job_data` blob,
PRIMARY KEY (`sched_name`,`job_name`,`job_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of qrtz_job_details
-- ----------------------------
INSERT INTO `qrtz_job_details` VALUES ('quartzScheduler', 'hw_job', 'hw_group', null, 'com.test.job.HelloWorldJob', '0', '0', '0', '0', 0x230D0A23546875204E6F762030312031343A30343A35352043535420323031380D0A);
INSERT INTO `qrtz_job_details` VALUES ('quartzScheduler', 'hw_job1', 'hw_group1', null, 'com.test.job.MyJob', '0', '0', '0', '0', 0x230D0A23546875204E6F762030312031343A34353A31362043535420323031380D0A);
-- ----------------------------
-- Table structure for `qrtz_locks`
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_locks`;
CREATE TABLE `qrtz_locks` (
`sched_name` varchar(120) NOT NULL,
`lock_name` varchar(40) NOT NULL,
PRIMARY KEY (`sched_name`,`lock_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of qrtz_locks
-- ----------------------------
INSERT INTO `qrtz_locks` VALUES ('quartzScheduler', 'TRIGGER_ACCESS');
-- ----------------------------
-- Table structure for `qrtz_paused_trigger_grps`
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`;
CREATE TABLE `qrtz_paused_trigger_grps` (
`sched_name` varchar(120) NOT NULL,
`trigger_group` varchar(80) NOT NULL,
PRIMARY KEY (`sched_name`,`trigger_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of qrtz_paused_trigger_grps
-- ----------------------------
-- ----------------------------
-- Table structure for `qrtz_scheduler_state`
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_scheduler_state`;
CREATE TABLE `qrtz_scheduler_state` (
`sched_name` varchar(120) NOT NULL,
`instance_name` varchar(80) NOT NULL,
`last_checkin_time` bigint(20) NOT NULL,
`checkin_interval` bigint(20) NOT NULL,
PRIMARY KEY (`sched_name`,`instance_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of qrtz_scheduler_state
-- ----------------------------
-- ----------------------------
-- Table structure for `qrtz_simple_triggers`
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_simple_triggers`;
CREATE TABLE `qrtz_simple_triggers` (
`sched_name` varchar(120) NOT NULL,
`trigger_name` varchar(80) NOT NULL,
`trigger_group` varchar(80) NOT NULL,
`repeat_count` bigint(20) NOT NULL,
`repeat_interval` bigint(20) NOT NULL,
`times_triggered` bigint(20) NOT NULL,
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of qrtz_simple_triggers
-- ----------------------------
-- ----------------------------
-- Table structure for `qrtz_simprop_triggers`
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_simprop_triggers`;
CREATE TABLE `qrtz_simprop_triggers` (
`sched_name` varchar(120) NOT NULL,
`TRIGGER_NAME` varchar(200) NOT NULL,
`TRIGGER_GROUP` varchar(200) NOT NULL,
`STR_PROP_1` varchar(512) DEFAULT NULL,
`STR_PROP_2` varchar(512) DEFAULT NULL,
`STR_PROP_3` varchar(512) DEFAULT NULL,
`INT_PROP_1` int(11) DEFAULT NULL,
`INT_PROP_2` int(11) DEFAULT NULL,
`LONG_PROP_1` bigint(20) DEFAULT NULL,
`LONG_PROP_2` bigint(20) DEFAULT NULL,
`DEC_PROP_1` decimal(13,4) DEFAULT NULL,
`DEC_PROP_2` decimal(13,4) DEFAULT NULL,
`BOOL_PROP_1` varchar(1) DEFAULT NULL,
`BOOL_PROP_2` varchar(1) DEFAULT NULL,
PRIMARY KEY (`sched_name`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of qrtz_simprop_triggers
-- ----------------------------
-- ----------------------------
-- Table structure for `qrtz_triggers`
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_triggers`;
CREATE TABLE `qrtz_triggers` (
`sched_name` varchar(120) NOT NULL,
`trigger_name` varchar(80) NOT NULL,
`trigger_group` varchar(80) NOT NULL,
`job_name` varchar(80) NOT NULL,
`job_group` varchar(80) NOT NULL,
`description` varchar(120) DEFAULT NULL,
`next_fire_time` bigint(20) DEFAULT NULL,
`prev_fire_time` bigint(20) DEFAULT NULL,
`priority` int(11) DEFAULT NULL,
`trigger_state` varchar(16) NOT NULL,
`trigger_type` varchar(8) NOT NULL,
`start_time` bigint(20) NOT NULL,
`end_time` bigint(20) DEFAULT NULL,
`calendar_name` varchar(80) DEFAULT NULL,
`misfire_instr` smallint(6) DEFAULT NULL,
`job_data` blob,
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
KEY `sched_name` (`sched_name`,`job_name`,`job_group`),
CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `job_name`, `job_group`) REFERENCES `qrtz_job_details` (`sched_name`, `job_name`, `job_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of qrtz_triggers
-- ----------------------------
INSERT INTO `qrtz_triggers` VALUES ('quartzScheduler', 'hw_tigger', 'hw_tigger_group', 'hw_job', 'hw_group', null, '1541052835000', '1541052830000', '5', 'PAUSED', 'CRON', '1541052295000', '0', null, '0', '');
INSERT INTO `qrtz_triggers` VALUES ('quartzScheduler', 'hw_tigger1', 'hw_tigger_group1', 'hw_job1', 'hw_group1', null, '1541054800000', '1541054795000', '5', 'PAUSED', 'CRON', '1541054716000', '0', null, '0', '');
-- ----------------------------
-- Table structure for `user_t`
-- ----------------------------
DROP TABLE IF EXISTS `user_t`;
CREATE TABLE `user_t` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(40) NOT NULL,
`password` varchar(255) NOT NULL,
`age` int(4) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user_t
-- ----------------------------
INSERT INTO `user_t` VALUES ('1', 'admin', '123456', '24');
QuartzController.java
package com.test.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSONObject;
import com.test.entity.JobEntity;
import com.test.service.QuartzService;
@Controller
@RequestMapping("quartz")
public class QuartzController {
@Autowired
private Scheduler quartzScheduler;
@Autowired
private QuartzService quartzService;
/**
* 定时列表页
*
* @return
* @throws SchedulerException
*/
@RequestMapping(value="/listJob")
public String listJob(HttpServletRequest request,HttpServletResponse response) throws SchedulerException {
List<JobEntity> jobInfos = this.getSchedulerJobInfo();
request.setAttribute("jobInfos", jobInfos);
return "quartz/listjob";
}
/**
* 跳转到新增
*
* @return
* @throws SchedulerException
* @throws ClassNotFoundException
*/
@RequestMapping(value="/toAdd")
public String toAdd(HttpServletRequest request,HttpServletResponse response) throws SchedulerException {
return "quartz/addjob";
}
/**
* 新增job
*
* @return
* @throws SchedulerException
* @throws ClassNotFoundException
*/
@RequestMapping(value="/add",method=RequestMethod.POST)
public String add(HttpServletRequest request,HttpServletResponse response) throws SchedulerException, ClassNotFoundException {
String jobName = request.getParameter("jobName");
String jobGroupName = request.getParameter("jobGroupName");
String triggerName = request.getParameter("triggerName");
String triggerGroupName = request.getParameter("triggerGroupName");
String clazz = request.getParameter("clazz");
Class cls = Class.forName(clazz);
String cron = request.getParameter("cron");
quartzService.addJob(jobName, jobGroupName, triggerName, triggerGroupName, cls, cron);
request.setAttribute("message", "添加任务成功!");
request.setAttribute("opName", "添加任务!");
return "quartz/message";
}
/**
* 跳转到编辑
*
* @return
* @throws SchedulerException
* @throws ClassNotFoundException
*/
@RequestMapping(value="/toEdit")
public String toEdit(HttpServletRequest request,HttpServletResponse response) throws SchedulerException {
String jobName = request.getParameter("jobName");
String jobGroup = request.getParameter("jobGroup");
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
JobDetail jd = quartzScheduler.getJobDetail(jobKey);
@SuppressWarnings("unchecked")
List<CronTrigger> triggers = (List<CronTrigger>) quartzScheduler
.getTriggersOfJob(jobKey);
CronTrigger trigger = triggers.get(0);
TriggerKey triggerKey = trigger.getKey();
String cron = trigger.getCronExpression();
Map<String, String> pd = new HashMap<String, String>();
pd.put("jobName", jobKey.getName());
pd.put("jobGroup", jobKey.getGroup());
pd.put("triggerName", triggerKey.getName());
pd.put("triggerGroupName", triggerKey.getGroup());
pd.put("cron", cron);
pd.put("clazz", jd.getJobClass().getCanonicalName());
request.setAttribute("pd", pd);
request.setAttribute("msg", "edit");
return "quartz/editjob";
}
/**
* 编辑job
*
* @return
* @throws SchedulerException
* @throws ClassNotFoundException
*/
@RequestMapping(value="/edit",method=RequestMethod.POST)
public String edit(HttpServletRequest request,HttpServletResponse response) throws SchedulerException, ClassNotFoundException {
String jobName = request.getParameter("jobName");
String jobGroupName = request.getParameter("jobGroupName");
String triggerName = request.getParameter("triggerName");
String triggerGroupName = request.getParameter("triggerGroupName");
String clazz = request.getParameter("clazz");
Class cls = Class.forName(clazz);
String cron = request.getParameter("cron");
String oldjobName = request.getParameter("oldjobName");
String oldjobGroup = request.getParameter("oldjobGroup");
String oldtriggerName = request.getParameter("oldtriggerName");
String oldtriggerGroup = request.getParameter("oldtriggerGroup");
boolean result = quartzService.modifyJobTime(oldjobName, oldjobGroup, oldtriggerName, oldtriggerGroup,
jobName, jobGroupName, triggerName, triggerGroupName, cron);
if(result){
request.setAttribute("message", "修改任务成功!");
}else{
request.setAttribute("message", "修改任务失败!");
}
request.setAttribute("opName", "更新任务!");
return "quartz/message";
}
@RequestMapping(value="/pauseJob",method=RequestMethod.POST)
@ResponseBody
public String pauseJob(@RequestParam("jobName") String jobName,@RequestParam("jobGroupName") String jobGroupName){
JSONObject json = new JSONObject();
if(StringUtils.isEmpty(jobName) || StringUtils.isEmpty(jobGroupName)){
json.put("status", "wrong");
}else{
quartzService.pauseJob(jobName, jobGroupName);
json.put("status", "success");
}
return json.toJSONString();
}
@RequestMapping(value="/resumeJob",method=RequestMethod.POST)
@ResponseBody
public String resumeJob(@RequestParam("jobName") String jobName,@RequestParam("jobGroupName") String jobGroupName){
JSONObject json = new JSONObject();
if(StringUtils.isEmpty(jobName) || StringUtils.isEmpty(jobGroupName)){
json.put("status", "wrong");
}else{
quartzService.resumeJob(jobName, jobGroupName);
json.put("status", "success");
}
return json.toJSONString();
}
@RequestMapping(value="/deleteJob",method=RequestMethod.POST)
@ResponseBody
public String deleteJob(@RequestParam("jobName") String jobName,@RequestParam("jobGroupName") String jobGroupName,
@RequestParam("triggerName") String triggerName,@RequestParam("triggerGroupName") String triggerGroupName ){
JSONObject json = new JSONObject();
if(StringUtils.isEmpty(jobName) || StringUtils.isEmpty(jobGroupName) ||
StringUtils.isEmpty(triggerName) || StringUtils.isEmpty(triggerGroupName) ){
json.put("status", "wrong");
}else{
quartzService.removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
json.put("status", "success");
}
return json.toJSONString();
}
private List<JobEntity> getSchedulerJobInfo() throws SchedulerException {
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);
if (t instanceof CronTrigger) {
CronTrigger trigger = (CronTrigger) t;
JobKey jobKey = trigger.getJobKey();
JobDetail jd = quartzScheduler.getJobDetail(jobKey);
JobEntity jobInfo = new JobEntity();
jobInfo.setJobName(jobKey.getName());
jobInfo.setJobGroup(jobKey.getGroup());
jobInfo.setTriggerName(triggerKey.getName());
jobInfo.setTriggerGroupName(triggerKey.getGroup());
jobInfo.setCronExpr(trigger.getCronExpression());
jobInfo.setNextFireTime(trigger.getNextFireTime());
jobInfo.setPreviousFireTime(trigger.getPreviousFireTime());
jobInfo.setStartTime(trigger.getStartTime());
jobInfo.setEndTime(trigger.getEndTime());
jobInfo.setJobClass(jd.getJobClass().getCanonicalName());
// jobInfo.setDuration(Long.parseLong(jd.getDescription()));
Trigger.TriggerState triggerState = quartzScheduler
.getTriggerState(trigger.getKey());
jobInfo.setJobStatus(triggerState.toString());// NONE无,
// NORMAL正常,
// PAUSED暂停,
// COMPLETE完全,
// ERROR错误,
// BLOCKED阻塞
JobDataMap map = quartzScheduler.getJobDetail(jobKey)
.getJobDataMap();
if (null != map&&map.size() != 0) {
jobInfo.setCount(Integer.parseInt((String) map
.get("count")));
jobInfo.setJobDataMap(map);
} else {
jobInfo.setJobDataMap(new JobDataMap());
}
jobInfos.add(jobInfo);
}
}
}
return jobInfos;
}
}
QuartzService.java
package com.test.service.impl;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.test.service.QuartzService;
@Service("quartzService")
public class QuartzServiceImpl implements QuartzService{
@Autowired
private Scheduler quartzScheduler;
@Override
public void addJob(String jobName, String jobGroupName, String triggerName,
String triggerGroupName, Class cls, String cron) {
try {
// 获取调度器
Scheduler sched = quartzScheduler;
// 创建一项作业
JobDetail job = JobBuilder.newJob(cls)
.withIdentity(jobName, jobGroupName).build();
// 创建一个触发器
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerName, triggerGroupName)
.withSchedule(CronScheduleBuilder.cronSchedule(cron))
.build();
// 告诉调度器使用该触发器来安排作业
sched.scheduleJob(job, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 修改定时器任务信息
* 触发器停止 触发器移除 原任务移除 新任务重新添加
*/
@Override
public boolean modifyJobTime(String oldjobName, String oldjobGroup, String oldtriggerName, String oldtriggerGroup, String jobName, String jobGroup,
String triggerName, String triggerGroup, String cron) {
try {
Scheduler sched = quartzScheduler;
CronTrigger trigger = (CronTrigger) sched.getTrigger(TriggerKey
.triggerKey(oldtriggerName, oldtriggerGroup));
if (trigger == null) {
return false;
}
JobKey jobKey = JobKey.jobKey(oldjobName, oldjobGroup);
TriggerKey triggerKey = TriggerKey.triggerKey(oldtriggerName,
oldtriggerGroup);
JobDetail job = sched.getJobDetail(jobKey);
Class jobClass = job.getJobClass();
// 停止触发器
sched.pauseTrigger(triggerKey);
// 移除触发器
sched.unscheduleJob(triggerKey);
// 删除任务
sched.deleteJob(jobKey);
addJob(jobName, jobGroup, triggerName, triggerGroup, jobClass,
cron);
return true;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 修改任务的执行时间
*/
@Override
public void modifyJobTime(String triggerName, String triggerGroupName,
String time) {
try {
Scheduler sched = quartzScheduler;
CronTrigger trigger = (CronTrigger) sched.getTrigger(TriggerKey
.triggerKey(triggerName, triggerGroupName));
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
CronTrigger ct = (CronTrigger) trigger;
// 修改时间
ct.getTriggerBuilder()
.withSchedule(CronScheduleBuilder.cronSchedule(time))
.build();
// 重启触发器
sched.resumeTrigger(TriggerKey.triggerKey(triggerName,
triggerGroupName));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 触发器停止 触发器移除 任务删除
*/
@Override
public void removeJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName) {
try {
Scheduler sched = quartzScheduler;
// 停止触发器
sched.pauseTrigger(TriggerKey.triggerKey(triggerName,
triggerGroupName));
// 移除触发器
sched.unscheduleJob(TriggerKey.triggerKey(triggerName,
triggerGroupName));
// 删除任务
sched.deleteJob(JobKey.jobKey(jobName, jobGroupName));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 启动任务
*/
@Override
public void startSchedule() {
try {
Scheduler sched = quartzScheduler;
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 停止任务
*/
@Override
public void shutdownSchedule() {
try {
Scheduler sched = quartzScheduler;
if (!sched.isShutdown()) {
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 暂停任务
*/
@Override
public void pauseJob(String jobName, String jobGroupName) {
try {
quartzScheduler.pauseJob( JobKey.jobKey(jobName, jobGroupName));
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 恢复任务
*/
@Override
public void resumeJob(String jobName, String jobGroupName) {
try {
quartzScheduler.resumeJob(JobKey.jobKey(jobName, jobGroupName));
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
QuartServcieImpl.java
package com.test.service.impl;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.test.service.QuartzService;
@Service("quartzService")
public class QuartzServiceImpl implements QuartzService{
@Autowired
private Scheduler quartzScheduler;
@Override
public void addJob(String jobName, String jobGroupName, String triggerName,
String triggerGroupName, Class cls, String cron) {
try {
// 获取调度器
Scheduler sched = quartzScheduler;
// 创建一项作业
JobDetail job = JobBuilder.newJob(cls)
.withIdentity(jobName, jobGroupName).build();
// 创建一个触发器
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerName, triggerGroupName)
.withSchedule(CronScheduleBuilder.cronSchedule(cron))
.build();
// 告诉调度器使用该触发器来安排作业
sched.scheduleJob(job, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 修改定时器任务信息
* 触发器停止 触发器移除 原任务移除 新任务重新添加
*/
@Override
public boolean modifyJobTime(String oldjobName, String oldjobGroup, String oldtriggerName, String oldtriggerGroup, String jobName, String jobGroup,
String triggerName, String triggerGroup, String cron) {
try {
Scheduler sched = quartzScheduler;
CronTrigger trigger = (CronTrigger) sched.getTrigger(TriggerKey
.triggerKey(oldtriggerName, oldtriggerGroup));
if (trigger == null) {
return false;
}
JobKey jobKey = JobKey.jobKey(oldjobName, oldjobGroup);
TriggerKey triggerKey = TriggerKey.triggerKey(oldtriggerName,
oldtriggerGroup);
JobDetail job = sched.getJobDetail(jobKey);
Class jobClass = job.getJobClass();
// 停止触发器
sched.pauseTrigger(triggerKey);
// 移除触发器
sched.unscheduleJob(triggerKey);
// 删除任务
sched.deleteJob(jobKey);
addJob(jobName, jobGroup, triggerName, triggerGroup, jobClass,
cron);
return true;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 修改任务的执行时间
*/
@Override
public void modifyJobTime(String triggerName, String triggerGroupName,
String time) {
try {
Scheduler sched = quartzScheduler;
CronTrigger trigger = (CronTrigger) sched.getTrigger(TriggerKey
.triggerKey(triggerName, triggerGroupName));
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
CronTrigger ct = (CronTrigger) trigger;
// 修改时间
ct.getTriggerBuilder()
.withSchedule(CronScheduleBuilder.cronSchedule(time))
.build();
// 重启触发器
sched.resumeTrigger(TriggerKey.triggerKey(triggerName,
triggerGroupName));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 触发器停止 触发器移除 任务删除
*/
@Override
public void removeJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName) {
try {
Scheduler sched = quartzScheduler;
// 停止触发器
sched.pauseTrigger(TriggerKey.triggerKey(triggerName,
triggerGroupName));
// 移除触发器
sched.unscheduleJob(TriggerKey.triggerKey(triggerName,
triggerGroupName));
// 删除任务
sched.deleteJob(JobKey.jobKey(jobName, jobGroupName));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 启动任务
*/
@Override
public void startSchedule() {
try {
Scheduler sched = quartzScheduler;
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 停止任务
*/
@Override
public void shutdownSchedule() {
try {
Scheduler sched = quartzScheduler;
if (!sched.isShutdown()) {
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 暂停任务
*/
@Override
public void pauseJob(String jobName, String jobGroupName) {
try {
quartzScheduler.pauseJob( JobKey.jobKey(jobName, jobGroupName));
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 恢复任务
*/
@Override
public void resumeJob(String jobName, String jobGroupName) {
try {
quartzScheduler.resumeJob(JobKey.jobKey(jobName, jobGroupName));
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
JobEntity.java
package com.test.entity;
import java.util.Date;
import org.quartz.JobDataMap;
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 Date previousFireTime;
private Date nextFireTime;
private String jobStatus;
private long runTimes;
private long duration;
private Date startTime;
private Date endTime;
private String jobMemo;
private String jobClass;
private String jobMethod;
private String jobObject;
private int count;
private JobDataMap jobDataMap;
public int getJobId() {
return jobId;
}
public void setJobId(int jobId) {
this.jobId = jobId;
}
public String getJobType() {
return jobType;
}
public void setJobType(String jobType) {
this.jobType = jobType;
}
public String getJobGroup() {
return jobGroup;
}
public void setJobGroup(String jobGroup) {
this.jobGroup = jobGroup;
}
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public String getTriggerName() {
return triggerName;
}
public void setTriggerName(String triggerName) {
this.triggerName = triggerName;
}
public String getTriggerGroupName() {
return triggerGroupName;
}
public void setTriggerGroupName(String triggerGroupName) {
this.triggerGroupName = triggerGroupName;
}
public String getCronExpr() {
return cronExpr;
}
public void setCronExpr(String cronExpr) {
this.cronExpr = cronExpr;
}
public Date getPreviousFireTime() {
return previousFireTime;
}
public void setPreviousFireTime(Date previousFireTime) {
this.previousFireTime = previousFireTime;
}
public Date getNextFireTime() {
return nextFireTime;
}
public void setNextFireTime(Date nextFireTime) {
this.nextFireTime = nextFireTime;
}
public String getJobStatus() {
return jobStatus;
}
public void setJobStatus(String jobStatus) {
this.jobStatus = jobStatus;
}
public long getRunTimes() {
return runTimes;
}
public void setRunTimes(long runTimes) {
this.runTimes = runTimes;
}
public long getDuration() {
return duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public String getJobMemo() {
return jobMemo;
}
public void setJobMemo(String jobMemo) {
this.jobMemo = jobMemo;
}
public String getJobClass() {
return jobClass;
}
public void setJobClass(String jobClass) {
this.jobClass = jobClass;
}
public String getJobMethod() {
return jobMethod;
}
public void setJobMethod(String jobMethod) {
this.jobMethod = jobMethod;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String getJobObject() {
return jobObject;
}
public void setJobObject(String jobObject) {
this.jobObject = jobObject;
}
public JobDataMap getJobDataMap() {
return jobDataMap;
}
public void setJobDataMap(JobDataMap jobDataMap) {
this.jobDataMap = jobDataMap;
}
}
MyJob.java
package com.test.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class MyJob implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("myjob:正在运行");
}
}
listJob.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>任务列表</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<style type="text/css">
table{width: 90%;margin: 0 auto;text-align: center;border-right:1px solid #999;border-bottom: 1px solid #999;}
table tr{}
table td,table th{border-left: 1px solid #999;border-top: 1px solid #999;}
.btn{border: 0;border-radius:4px;background-color: #428bca;color: #fff;padding: 3px 5px;cursor: pointer;}
</style>
</head>
<body style="background: beige;">
<div style="text-align: center;">
<span>欢迎${name }登录!</span>
<span><a href="${pageContext.request.contextPath }/user/logout">退出</a></span>
</div>
<h2 style="text-align: center;">任务列表</h2>
<table id="table_report" class="table table-striped table-bordered table-hover" cellpadding="0" cellspacing="0">
<thead>
<tr>
<!-- th class="center">序号</th-->
<th class="center">任务组名称</th>
<th class="center">定时任务名称</th>
<!-- <th class="center">触发器组名称</th>
<th class="center">触发器名称</th> -->
<th class="center">时间表达式</th>
<th class="center">上次运行时间</th>
<th class="center">下次运行时间</th>
<th class="center">任务状态</th>
<!-- <th class="center">已经运行时间</th> -->
<!-- <th class="center">持续运行时间</th> -->
<th class="center">开始时间</th>
<th class="center">结束时间</th>
<th class="center">任务类名</th>
<!-- <th class="center">方法名称</th> -->
<!-- <th class="center">jobObject</th> -->
<!-- <th class="center">运行次数</th> -->
<th class="center" width="15%">操作</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='center' style="width: auto;">${var.jobGroup}</td>
<td class='center' style="width: auto;">${var.jobName}</td>
<%-- <td class='center' style="width: auto;">${var.triggerGroupName}</td>
<td class='center' style="width: auto;">${var.triggerName}</td> --%>
<td class='center' style="width: auto;">${var.cronExpr}</td>
<td class='center' style="width: auto;"><fmt:formatDate value="${var.previousFireTime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td class='center' style="width: auto;"><fmt:formatDate value="${var.nextFireTime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td class='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-inverse">锁定状态</span>
</c:if>
</td>
<%-- <td class='center' style="width: auto;">${var.runTimes}</td> --%>
<%-- <td class='center' style="width: auto;">${var.duration}</td> --%>
<td class='center' style="width: auto;"><fmt:formatDate value="${var.startTime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td class='center' style="width: auto;"><fmt:formatDate value="${var.endTime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td class='center' style="width: auto;">${var.jobClass}</td>
<%-- <td class='center' style="width: auto;">${var.jobMethod}</td> --%>
<%-- <td class='center' style="width: auto;">${var.jobObject}</td> --%>
<%-- <td class='center' style="width: auto;">${var.count}</td> --%>
<td class='center' style="width: auto;">
<%-- <a class="btn btn-minier btn-info" onclick="triggerJob('${var.jobName}','${var.jobGroup}');"><i class="icon-edit"></i>运行</a> --%>
<a class="btn btn-minier btn-success" onclick="edit('${var.jobName}','${var.jobGroup}');"><i class="icon-edit"></i>编辑</a><br>
<a class="btn btn-minier btn-warning" onclick="pauseJob('${var.jobName}','${var.jobGroup}');"><i class="icon-edit"></i>暂停</a>
<a class="btn btn-minier btn-purple" onclick="resumeJob('${var.jobName}','${var.jobGroup}');"><i class="icon-edit"></i>恢复</a>
<a class="btn btn-minier btn-danger" onclick="deleteJob('${var.jobName}','${var.jobGroup}','${var.triggerName}','${var.triggerGroupName}');"><i class="icon-edit"></i>删除</a>
</td>
</tr>
</c:forEach>
</c:when>
<c:otherwise>
<tr class="main_info">
<td colspan="100" class="center">没有相关数据</td>
</tr>
</c:otherwise>
</c:choose>
</tbody>
</table>
<div style="width: 90%;margin: 0 auto;text-align: center;margin-top: 25px;">
<button type="button" onclick="add();" class="btn">新增任务</button>
</div>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/js/jquery.min.js"></script>
<script type="text/javascript">
var url = "${pageContext.request.contextPath}";
function add(){
window.location.href = url + "/quartz/toAdd";
}
function edit(jobName,jobGroup){
window.location.href = url + "/quartz/toEdit?jobName="+jobName+"&jobGroup="+jobGroup;
}
//暂停任务
function pauseJob(jobName,jobGroupName){
$.post(url + "/quartz/pauseJob",{"jobName":jobName,"jobGroupName":jobGroupName},function(data){
if(data.status = 'success'){
window.location.href = window.location.href;
}else{
alert("操作失败,请刷新重新!");
}
});
}
//恢复任务
function resumeJob(jobName,jobGroupName){
$.post(url + "/quartz/resumeJob",{"jobName":jobName,"jobGroupName":jobGroupName},function(data){
if(data.status = 'success'){
window.location.href = window.location.href;
}else{
alert("操作失败,请刷新重新!");
}
});
}
//删除
function deleteJob(jobName,jobGroupName,triggerName,triggerGroupName){
$.post(url + "/quartz/deleteJob",{"jobName":jobName,"jobGroupName":jobGroupName,"triggerName":triggerName,"triggerGroupName":triggerGroupName},
function(data){
if(data.status = 'success'){
window.location.href = window.location.href;
}else{
alert("操作失败,请刷新重新!");
}
});
}
/* //执行任务
function triggerJob(a,b){
var url = "triggerJob";
var d = {jobName:a,jobGroupName:b};
$.post(url,d,function(data){
if(data.status = 'ok'){
window.location.href = window.location.href;
}
});
} */
</script>
</body>
</html>
到此,项目启动即可运行
本人文笔不行,对quartz的理解程度不够,所以没有过多的理论,更详细的请参见
项目下载