├── pictures ├── 1.png ├── 2.png └── 3.png ├── src ├── main │ ├── resources │ │ ├── static │ │ │ ├── favicon.ico │ │ │ └── js │ │ │ │ ├── index.js │ │ │ │ ├── bootstrap-select.min.js │ │ │ │ └── bootstrap.min.js │ │ ├── application.properties │ │ ├── generator │ │ │ └── generatorConfig.xml │ │ ├── templates │ │ │ └── index.html │ │ └── mapper │ │ │ └── ScheduleJobMapper.xml │ └── java │ │ └── cn │ │ └── bupt │ │ └── zcc │ │ └── dynamicquartz │ │ ├── service │ │ ├── QuartzService.java │ │ ├── ScheduleJobInService.java │ │ ├── SchedulerJobService.java │ │ └── impl │ │ │ ├── QuartzServiceImpl.java │ │ │ ├── ScheduleJobInServiceImpl.java │ │ │ └── SchedulerJobServiceImpl.java │ │ ├── DynamicquartzApplication.java │ │ ├── job │ │ ├── TestCronJob.java │ │ ├── HelloCronJob.java │ │ └── QuartzJobFactory.java │ │ ├── dao │ │ └── ScheduleJobMapper.java │ │ ├── util │ │ ├── Message.java │ │ └── ApplicationContextUtil.java │ │ ├── controller │ │ ├── IndexController.java │ │ └── JobController.java │ │ └── model │ │ ├── ScheduleJob.java │ │ └── ScheduleJobExample.java └── test │ └── java │ └── cn │ └── bupt │ └── zcc │ └── dynamicquartz │ └── DynamicquartzApplicationTests.java ├── .gitignore ├── pom.xml ├── README.md └── dynamicquartz.sql /pictures/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetcczhang/dynamicquartz/HEAD/pictures/1.png -------------------------------------------------------------------------------- /pictures/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetcczhang/dynamicquartz/HEAD/pictures/2.png -------------------------------------------------------------------------------- /pictures/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetcczhang/dynamicquartz/HEAD/pictures/3.png -------------------------------------------------------------------------------- /src/main/resources/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetcczhang/dynamicquartz/HEAD/src/main/resources/static/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/service/QuartzService.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.service; 2 | 3 | /** 4 | * @program: dynamicquartz 5 | * @description: 6 | * @author: Zhang Chengcheng 7 | * @create: 2018-05-31 14:47 8 | **/ 9 | public interface QuartzService { 10 | 11 | void executeTask(String beanName,String methodName); 12 | 13 | void executeTask(String beanName); 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/cn/bupt/zcc/dynamicquartz/DynamicquartzApplicationTests.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class DynamicquartzApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/DynamicquartzApplication.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @MapperScan("cn.bupt.zcc.dynamicquartz.dao") 8 | @SpringBootApplication 9 | public class DynamicquartzApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(DynamicquartzApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/job/TestCronJob.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.job; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.stereotype.Service; 6 | 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | 10 | /** 11 | * Created by 张城城 on 2018/6/1. 12 | */ 13 | @Service("testCronJob") 14 | public class TestCronJob { 15 | private static final Logger logger = LoggerFactory.getLogger(HelloCronJob.class); 16 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd:HH-ss"); 17 | public void execute(){ 18 | logger.info("[TestCronJob]测试这个任务调度框架是否管用!"); 19 | logger.info("----------------------------------:{}",sdf.format(new Date())); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/job/HelloCronJob.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.job; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.stereotype.Service; 6 | 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | 10 | /** 11 | * Created by 张城城 on 2018/6/1. 12 | */ 13 | @Service("helloCronJob") 14 | public class HelloCronJob { 15 | private static final Logger logger = LoggerFactory.getLogger(HelloCronJob.class); 16 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd:HH-ss"); 17 | public void execute(){ 18 | logger.info("[HelloCronJob]测试这个任务调度框架是否管用!"); 19 | logger.info("----------------------------------:{}",sdf.format(new Date())); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/service/ScheduleJobInService.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.service; 2 | 3 | import cn.bupt.zcc.dynamicquartz.model.ScheduleJob; 4 | 5 | /** 6 | * Created by 张城城 on 2018/6/1. 7 | */ 8 | public interface ScheduleJobInService { 9 | 10 | int insert(ScheduleJob scheduleJob); 11 | 12 | int insertSelective(ScheduleJob scheduleJob); 13 | 14 | ScheduleJob selectByJobNameAngJobGroup(String jobName, String groupName); 15 | 16 | ScheduleJob selectByPrimaryKey(Integer id); 17 | 18 | int updateByPrimaryKey(ScheduleJob scheduleJob); 19 | 20 | int updateByExample(ScheduleJob scheduleJob); 21 | 22 | int deleteByPrimaryKey(Integer id); 23 | 24 | int deleteByJobNameAndJobGroup(String jobName, String jobGroup); 25 | 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/service/SchedulerJobService.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.service; 2 | 3 | import cn.bupt.zcc.dynamicquartz.model.ScheduleJob; 4 | import org.quartz.SchedulerException; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @program: dynamicquartz 10 | * @description: ${description} 11 | * @author: Zhang Chengcheng 12 | * @create: 2018-05-31 16:12 13 | **/ 14 | public interface SchedulerJobService { 15 | 16 | List getAllScheduleJob(); 17 | 18 | void checkNotNull(ScheduleJob scheduleJob); 19 | 20 | List getAllRunningJob() throws SchedulerException; 21 | 22 | void saveOrUpdate(ScheduleJob scheduleJob) throws Exception; 23 | 24 | public void pauseJob(String jobName, String jobGroup) throws SchedulerException; 25 | 26 | public void deleteJob(String jobName,String jobGroup) throws SchedulerException; 27 | 28 | public void runOneJob(String jobName, String jobGroup) throws SchedulerException; 29 | 30 | public void resumeJob(String jobName, String jobGroup) throws SchedulerException; 31 | 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/dao/ScheduleJobMapper.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.dao; 2 | 3 | import cn.bupt.zcc.dynamicquartz.model.ScheduleJob; 4 | import cn.bupt.zcc.dynamicquartz.model.ScheduleJobExample; 5 | import java.util.List; 6 | import org.apache.ibatis.annotations.Param; 7 | 8 | public interface ScheduleJobMapper { 9 | int countByExample(ScheduleJobExample example); 10 | 11 | int deleteByExample(ScheduleJobExample example); 12 | 13 | int deleteByPrimaryKey(Integer id); 14 | 15 | Integer insert(ScheduleJob record); 16 | 17 | Integer insertSelective(ScheduleJob record); 18 | 19 | List selectByExample(ScheduleJobExample example); 20 | 21 | ScheduleJob selectByPrimaryKey(Integer id); 22 | 23 | int updateByExampleSelective(@Param("record") ScheduleJob record, @Param("example") ScheduleJobExample example); 24 | 25 | int updateByExample(@Param("record") ScheduleJob record, @Param("example") ScheduleJobExample example); 26 | 27 | int updateByPrimaryKeySelective(ScheduleJob record); 28 | 29 | int updateByPrimaryKey(ScheduleJob record); 30 | } -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/job/QuartzJobFactory.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.job; 2 | 3 | import cn.bupt.zcc.dynamicquartz.model.ScheduleJob; 4 | import cn.bupt.zcc.dynamicquartz.service.QuartzService; 5 | import org.quartz.JobExecutionContext; 6 | import org.quartz.JobExecutionException; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.scheduling.quartz.QuartzJobBean; 9 | import org.springframework.stereotype.Service; 10 | 11 | /** 12 | * 13 | * 14 | * @author: Zhang Chengcheng 15 | * @create: 2018-05-31 14:38 16 | **/ 17 | @Service("quartzJobFactory") 18 | public class QuartzJobFactory extends QuartzJobBean { 19 | 20 | @Autowired 21 | QuartzService quartzService; 22 | 23 | @Override 24 | protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { 25 | ScheduleJob object = (ScheduleJob) jobExecutionContext.getMergedJobDataMap().get("scheduleJob"); 26 | if(object.getMethodName()==null || object.getMethodName().equals("")){ 27 | quartzService.executeTask(object.getBeanName()); 28 | }else { 29 | quartzService.executeTask(object.getBeanName(),object.getMethodName()); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/util/Message.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.util; 2 | 3 | import java.io.Serializable; 4 | 5 | public class Message implements Serializable{ 6 | 7 | private static final long serialVersionUID = 1L; 8 | 9 | public static Message failure(String msg) { 10 | return new Message(false, msg); 11 | } 12 | public static Message failure(Exception e) { 13 | return new Message(false, e.getMessage()); 14 | } 15 | public static Message failure() { 16 | return new Message(false); 17 | } 18 | public static Message success() { 19 | return new Message(true); 20 | } 21 | public static Message success(String msg) { 22 | return new Message(true, msg); 23 | } 24 | public Message(boolean valid, String msg) { 25 | super(); 26 | this.valid = valid; 27 | this.msg = msg; 28 | } 29 | public Message(boolean valid) { 30 | super(); 31 | this.valid = valid; 32 | } 33 | public boolean isValid() { 34 | return valid; 35 | } 36 | public void setValid(boolean valid) { 37 | this.valid = valid; 38 | } 39 | public String getMsg() { 40 | return msg; 41 | } 42 | public void setMsg(String msg) { 43 | this.msg = msg; 44 | } 45 | 46 | boolean valid; 47 | String msg; 48 | Object data; 49 | 50 | public Object getData() { 51 | return data; 52 | } 53 | public void setData(Object data) { 54 | this.valid = true; 55 | this.data = data; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/controller/IndexController.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.controller; 2 | 3 | import cn.bupt.zcc.dynamicquartz.model.ScheduleJob; 4 | import cn.bupt.zcc.dynamicquartz.service.SchedulerJobService; 5 | import org.quartz.Scheduler; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Controller; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | import java.util.List; 14 | 15 | /** 16 | * Created by 张城城 on 2018/6/2. 17 | */ 18 | @Controller 19 | public class IndexController { 20 | 21 | private static final Logger logger = LoggerFactory.getLogger(IndexController.class); 22 | 23 | @Autowired 24 | private Scheduler scheduler; 25 | 26 | @Autowired 27 | private SchedulerJobService schedulerJobService; 28 | 29 | @RequestMapping("/") 30 | public String index(HttpServletRequest request){ 31 | logger.info("[JobController] the url path:------------/index----------------"); 32 | logger.info("[JobController] the method index is start......"); 33 | List jobList = schedulerJobService.getAllScheduleJob(); 34 | request.setAttribute("jobs",jobList); 35 | System.out.println(jobList); 36 | logger.info("[JobController] the method index is end......"); 37 | return "index"; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/util/ApplicationContextUtil.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.util; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * 10 | * @author: Zhang Chengcheng 11 | * @create: 2018-05-31 15:07 12 | **/ 13 | @Component("ApplicationContextUtil") 14 | public class ApplicationContextUtil implements ApplicationContextAware { 15 | 16 | private static ApplicationContext applicationContext; 17 | @Override 18 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 19 | ApplicationContextUtil.applicationContext = applicationContext; 20 | } 21 | public ApplicationContext getApplicationContext(){ 22 | checkApplicationContext(); 23 | return applicationContext; 24 | } 25 | 26 | public void checkApplicationContext(){ 27 | if (applicationContext==null){ 28 | throw new IllegalStateException("applicationContext 未注入,请在applicationContext.xml中定义SpringContextUtil"); 29 | } 30 | } 31 | /** 32 | *根据bean的名称去寻找一个类的实例 33 | * @param name 34 | * @param 35 | * @return 36 | */ 37 | public static T getBean(String name){ 38 | 39 | return (T) applicationContext.getBean(name); 40 | } 41 | 42 | /** 43 | * 根据全限定类名去寻找一个spring管理的bean实例 44 | * @param clazz 45 | * @param 46 | * @return 47 | */ 48 | public static T getBean(Class clazz){ 49 | 50 | return (T)applicationContext.getBean(clazz); 51 | } 52 | 53 | /** 54 | *根据bean的名称和全限定类名去寻找一个类的实例 55 | * @param name 56 | * @param clazz 57 | * @param 58 | * @return 59 | */ 60 | public static T getBean(String name,Class clazz){ 61 | return (T) applicationContext.getBean(name,clazz); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/service/impl/QuartzServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.service.impl; 2 | 3 | import cn.bupt.zcc.dynamicquartz.service.QuartzService; 4 | import cn.bupt.zcc.dynamicquartz.util.ApplicationContextUtil; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.lang.reflect.InvocationTargetException; 10 | import java.lang.reflect.Method; 11 | 12 | 13 | /** 14 | * @program: dynamicquartz 15 | * 16 | * @author: Zhang Chengcheng 17 | * 18 | * 19 | * @create: 2018-05-31 15:34 20 | **/ 21 | @Service("quartzService") 22 | public class QuartzServiceImpl implements QuartzService { 23 | 24 | private static final Logger logger = LoggerFactory.getLogger(QuartzServiceImpl.class); 25 | private static final String METHODNAME = "execute"; 26 | 27 | @Override 28 | public void executeTask(String beanName, String methodName) { 29 | Object object = ApplicationContextUtil.getBean(beanName); 30 | try { 31 | logger.info("[QuartzServiceImpl] 反射调beanName:{},methodName:{}法开始.........",beanName,methodName); 32 | if (beanName.contains("\\.")){ 33 | Class clazz = Class.forName(beanName); 34 | Object cronJob = ApplicationContextUtil.getBean(clazz); 35 | Method method1 = clazz.getMethod(methodName); 36 | method1.invoke(cronJob); 37 | }else { 38 | Method method = object.getClass().getMethod(methodName); 39 | method.invoke(object); 40 | } 41 | 42 | } catch (Exception e) { 43 | logger.error("[QuartzServiceImpl] method invoke error,beanName:{},methodName:{}",beanName,methodName); 44 | return; 45 | } 46 | logger.info("[QuartzServiceImpl] 反射调beanName:{},methodName:{}法结束.........",beanName,methodName); 47 | 48 | } 49 | 50 | @Override 51 | public void executeTask(String beanName) { 52 | executeTask(beanName, METHODNAME); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # 数据库连接的配置 2 | spring.datasource.druid.url=jdbc:mysql://localhost:3306/dynamicquartz?useUnicode=true&characterEncoding=utf8 3 | spring.datasource.druid.username=root 4 | spring.datasource.druid.password=2012061128 5 | spring.datasource.type=com.alibaba.druid.pool.DruidDataSource 6 | spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver 7 | spring.datasource.druid.filters=stat 8 | spring.datasource.druid.max-active=20 9 | spring.datasource.druid.initialSize=1 10 | spring.datasource.druid.max-wait=60000 11 | spring.datasource.druid.min-idle=1 12 | spring.datasource.druid.time-between-eviction-runs-millis=60000 13 | spring.datasource.druid.min-evictable-idle-time-millis=300000 14 | spring.datasource.druid.validation-query=select 'x' 15 | spring.datasource.druid.test-while-idle=true 16 | spring.datasource.druid.test-on-return=false 17 | spring.datasource.druid.test-on-borrow=false 18 | 19 | # mybatis配置 20 | mybatis.mapper-locations=classpath:mapper/*.xml 21 | mybatis.type-aliases-package=cn.bupt.zcc.dynamicquartz.model 22 | 23 | # quartz的一些属性配置 24 | spring.quartz.job-store-type=jdbc 25 | spring.quartz.properties.org.quartz.scheduler.instanceName=clusteredScheduler 26 | spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO 27 | spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX 28 | spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate 29 | spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_ 30 | #spring.quartz.properties.org.quartz.jobStore.isClustered=true 31 | #spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=10000 32 | spring.quartz.properties.org.quartz.jobStore.useProperties=false 33 | 34 | # 集成thymeleaf引擎的一些配置 35 | spring.thymeleaf.prefix=classpath:/templates/ 36 | spring.thymeleaf.check-template-location=true 37 | spring.thymeleaf.suffix=.html 38 | spring.thymeleaf.encoding=UTF-8 39 | spring.thymeleaf.servlet.content-type=text/html 40 | spring.thymeleaf.mode=HTML5 41 | spring.thymeleaf.cache=false 42 | -------------------------------------------------------------------------------- /src/main/resources/generator/generatorConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
35 |
36 | 37 | 38 |
39 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/service/impl/ScheduleJobInServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.service.impl; 2 | 3 | import cn.bupt.zcc.dynamicquartz.dao.ScheduleJobMapper; 4 | import cn.bupt.zcc.dynamicquartz.model.ScheduleJob; 5 | import cn.bupt.zcc.dynamicquartz.model.ScheduleJobExample; 6 | import cn.bupt.zcc.dynamicquartz.service.ScheduleJobInService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * 14 | * Created by 张城城 on 2018/6/1. 15 | */ 16 | @Service("scheduleJobInService") 17 | public class ScheduleJobInServiceImpl implements ScheduleJobInService { 18 | 19 | @Autowired 20 | ScheduleJobMapper scheduleJobMapper; 21 | 22 | @Override 23 | public int insert(ScheduleJob scheduleJob) { 24 | int id = scheduleJobMapper.insertSelective(scheduleJob); 25 | return id; 26 | } 27 | 28 | @Override 29 | public int insertSelective(ScheduleJob scheduleJob) { 30 | int id = scheduleJobMapper.insertSelective(scheduleJob); 31 | return id; 32 | } 33 | 34 | @Override 35 | public ScheduleJob selectByJobNameAngJobGroup(String jobName, String groupName) { 36 | ScheduleJobExample scheduleJobExample = new ScheduleJobExample(); 37 | scheduleJobExample.createCriteria().andJobGroupEqualTo(groupName).andJobNameEqualTo(jobName); 38 | List list = scheduleJobMapper.selectByExample(scheduleJobExample); 39 | if (list.size()>0){ 40 | return list.get(0); 41 | } 42 | return null; 43 | } 44 | 45 | @Override 46 | public ScheduleJob selectByPrimaryKey(Integer id) { 47 | return scheduleJobMapper.selectByPrimaryKey(id); 48 | } 49 | 50 | @Override 51 | public int updateByPrimaryKey(ScheduleJob scheduleJob) { 52 | return scheduleJobMapper.updateByPrimaryKeySelective(scheduleJob); 53 | } 54 | 55 | @Override 56 | public int updateByExample(ScheduleJob scheduleJob) { 57 | ScheduleJobExample scheduleJobExample = new ScheduleJobExample(); 58 | scheduleJobExample.createCriteria().andJobNameEqualTo(scheduleJob.getJobName()).andJobGroupEqualTo(scheduleJob.getJobGroup()); 59 | return scheduleJobMapper.updateByExample(scheduleJob,scheduleJobExample); 60 | } 61 | 62 | @Override 63 | public int deleteByPrimaryKey(Integer id) { 64 | return scheduleJobMapper.deleteByPrimaryKey(id); 65 | } 66 | 67 | @Override 68 | public int deleteByJobNameAndJobGroup(String jobName, String jobGroup) { 69 | ScheduleJobExample scheduleJobExample = new ScheduleJobExample(); 70 | scheduleJobExample.createCriteria().andJobGroupEqualTo(jobGroup).andJobNameEqualTo(jobName); 71 | return scheduleJobMapper.deleteByExample(scheduleJobExample); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/model/ScheduleJob.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.model; 2 | 3 | import java.io.Serializable; 4 | 5 | public class ScheduleJob implements Serializable { 6 | private static final long serialVersionUID = 1L; 7 | private Integer id; 8 | 9 | private String jobId; 10 | 11 | private String jobName; 12 | 13 | private String jobStatus; 14 | 15 | private String jobGroup; 16 | 17 | private String cronExpression; 18 | 19 | private String description; 20 | 21 | private String beanName; 22 | 23 | private String methodName; 24 | 25 | public Integer getId() { 26 | return id; 27 | } 28 | 29 | public void setId(Integer id) { 30 | this.id = id; 31 | } 32 | 33 | public String getJobId() { 34 | return jobId; 35 | } 36 | 37 | public void setJobId(String jobId) { 38 | this.jobId = jobId; 39 | } 40 | 41 | public String getJobName() { 42 | return jobName; 43 | } 44 | 45 | public void setJobName(String jobName) { 46 | this.jobName = jobName; 47 | } 48 | 49 | public String getJobStatus() { 50 | return jobStatus; 51 | } 52 | 53 | public void setJobStatus(String jobStatus) { 54 | this.jobStatus = jobStatus; 55 | } 56 | 57 | public String getJobGroup() { 58 | return jobGroup; 59 | } 60 | 61 | public void setJobGroup(String jobGroup) { 62 | this.jobGroup = jobGroup; 63 | } 64 | 65 | public String getCronExpression() { 66 | return cronExpression; 67 | } 68 | 69 | public void setCronExpression(String cronExpression) { 70 | this.cronExpression = cronExpression; 71 | } 72 | 73 | public String getDescription() { 74 | return description; 75 | } 76 | 77 | public void setDescription(String description) { 78 | this.description = description; 79 | } 80 | 81 | public String getBeanName() { 82 | return beanName; 83 | } 84 | 85 | public void setBeanName(String beanName) { 86 | this.beanName = beanName; 87 | } 88 | 89 | public String getMethodName() { 90 | return methodName; 91 | } 92 | 93 | public void setMethodName(String methodName) { 94 | this.methodName = methodName; 95 | } 96 | 97 | @Override 98 | public String toString() { 99 | return "ScheduleJob{" + 100 | "id=" + id + 101 | ", jobId='" + jobId + '\'' + 102 | ", jobName='" + jobName + '\'' + 103 | ", jobStatus='" + jobStatus + '\'' + 104 | ", jobGroup='" + jobGroup + '\'' + 105 | ", cronExpression='" + cronExpression + '\'' + 106 | ", description='" + description + '\'' + 107 | ", beanName='" + beanName + '\'' + 108 | ", methodName='" + methodName + '\'' + 109 | '}'; 110 | } 111 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | cn.bupt.zcc 7 | dynamicquartz 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | dynamicquartz 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.2.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-web 32 | 33 | 34 | 35 | 36 | org.mybatis.spring.boot 37 | mybatis-spring-boot-starter 38 | 1.3.2 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-jdbc 43 | 44 | 45 | mysql 46 | mysql-connector-java 47 | runtime 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-quartz 55 | 56 | 57 | org.springframework 58 | spring-context-support 59 | 60 | 61 | 62 | 63 | com.alibaba 64 | druid-spring-boot-starter 65 | 1.1.9 66 | 67 | 68 | 69 | org.apache.commons 70 | commons-lang3 71 | 3.4 72 | 73 | 74 | 75 | org.springframework.boot 76 | spring-boot-starter-websocket 77 | 78 | 79 | org.springframework.boot 80 | spring-boot-starter-thymeleaf 81 | 82 | 83 | 84 | org.springframework.boot 85 | spring-boot-starter-test 86 | test 87 | 88 | 89 | 90 | 91 | 92 | 93 | src/main/java 94 | 95 | **/*.xml 96 | 97 | true 98 | 99 | 100 | 101 | src/main/resources 102 | true 103 | 104 | 105 | 106 | 107 | org.springframework.boot 108 | spring-boot-maven-plugin 109 | 110 | 111 | org.mybatis.generator 112 | mybatis-generator-maven-plugin 113 | 1.3.2 114 | 115 | ${basedir}/src/main/resources/generator/generatorConfig.xml 116 | true 117 | true 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /src/main/resources/static/js/index.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | //run job once 4 | $(".btnRun").click(function() { 5 | var jobId = $(this).parent().data("id"); 6 | $.ajax({ 7 | url: "/api/runOneJob?t=" + new Date().getTime(), 8 | type: "POST", 9 | data: { 10 | "jobName": $("#name_"+jobId).text(), 11 | "jobGroup": $("#group_"+jobId).text() 12 | }, 13 | success: function(res) { 14 | if (res.valid) { 15 | alert("run success!"); 16 | } else { 17 | alert(res.msg); 18 | } 19 | } 20 | }); 21 | }); 22 | 23 | //pause job 24 | $(".btnPause").click(function() { 25 | var jobId = $(this).parent().data("id"); 26 | $.ajax({ 27 | url: "/api/pauseJob?t=" + new Date().getTime(), 28 | type: "POST", 29 | data: { 30 | "jobName": $("#name_"+jobId).text(), 31 | "jobGroup": $("#group_"+jobId).text() 32 | }, 33 | success: function(res) { 34 | if (res.valid) { 35 | alert("pause success!"); 36 | location.reload(); 37 | } else { 38 | alert(res.msg); 39 | } 40 | } 41 | }); 42 | }); 43 | 44 | //resume job 45 | $(".btnResume").click(function() { 46 | var jobId = $(this).parent().data("id"); 47 | $.ajax({ 48 | url: "/api/resumeJob?t=" + new Date().getTime(), 49 | type: "POST", 50 | data: { 51 | "jobName": $("#name_"+jobId).text(), 52 | "jobGroup": $("#group_"+jobId).text() 53 | }, 54 | success: function(res) { 55 | if (res.valid) { 56 | alert("resume success!"); 57 | location.reload(); 58 | } else { 59 | alert(res.msg); 60 | } 61 | } 62 | }); 63 | }); 64 | 65 | //delete job 66 | $(".btnDelete").click(function() { 67 | var jobId = $(this).parent().data("id"); 68 | $.ajax({ 69 | url: "/api/deleteJob?t=" + new Date().getTime(), 70 | type: "POST", 71 | data: { 72 | "jobName": $("#name_"+jobId).text(), 73 | "jobGroup": $("#group_"+jobId).text() 74 | }, 75 | success: function(res) { 76 | if (res.valid) { 77 | alert("delete success!"); 78 | location.reload(); 79 | } else { 80 | alert(res.msg); 81 | } 82 | } 83 | }); 84 | }); 85 | 86 | // update cron expression 87 | $(".btnEdit").click( 88 | function() { 89 | $("#myModalLabel").html("cron edit"); 90 | var jobId = $(this).parent().data("id"); 91 | $("#jobId").val(jobId); 92 | $("#edit_name").val($("#name_"+jobId).text()); 93 | $("#edit_group").val($("#group_"+jobId).text()); 94 | $("#edit_bean").val($("#bean_"+jobId).text()); 95 | $("#edit_method").val($("#method_"+jobId).text()); 96 | $("#edit_cron").val($("#cron_"+jobId).text()); 97 | $("#edit_status").val($("#status_"+jobId).text()); 98 | $("#edit_desc").val($("#desc_"+jobId).text()); 99 | 100 | $('#edit_name').attr("readonly","readonly"); 101 | $('#edit_group').attr("readonly","readonly"); 102 | $('#edit_desc').attr("readonly","readonly"); 103 | 104 | $("#myModal").modal("show"); 105 | }); 106 | 107 | $("#save").click( 108 | function() { 109 | console.log($('#mainForm').serialize()); 110 | $.ajax({ 111 | url: "/api/saveOrUpdate?t=" + new Date().getTime(), 112 | type: "POST", 113 | data: $('#mainForm').serialize(), 114 | success: function(res) { 115 | if (res.valid) { 116 | alert("success!"); 117 | location.reload(); 118 | } else { 119 | alert(res.msg); 120 | } 121 | } 122 | }); 123 | }); 124 | 125 | 126 | // create job 127 | $("#createBtn").click( 128 | function() { 129 | $("#myModalLabel").html("create job"); 130 | 131 | $("#jobId").val(""); 132 | $("#edit_name").val(""); 133 | $("#edit_group").val(""); 134 | $("#edit_bean").val(); 135 | $("#edit_method").val(); 136 | $("#edit_cron").val(""); 137 | $("#edit_status").val("NORMAL"); 138 | $("#edit_desc").val(""); 139 | 140 | $('#edit_name').removeAttr("readonly"); 141 | $('#edit_group').removeAttr("readonly"); 142 | $('#edit_desc').removeAttr("readonly"); 143 | 144 | $("#myModal").modal("show"); 145 | }); 146 | 147 | 148 | }); -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/controller/JobController.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.controller; 2 | 3 | import cn.bupt.zcc.dynamicquartz.model.ScheduleJob; 4 | import cn.bupt.zcc.dynamicquartz.service.SchedulerJobService; 5 | import cn.bupt.zcc.dynamicquartz.util.Message; 6 | import org.quartz.*; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.web.bind.annotation.ModelAttribute; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.ResponseBody; 14 | 15 | import javax.servlet.http.HttpServletRequest; 16 | import java.util.List; 17 | 18 | /** 19 | * Created by 张城城 on 2018/5/31. 20 | */ 21 | @RequestMapping("/api") 22 | @Controller 23 | public class JobController { 24 | private static final Logger logger = LoggerFactory.getLogger(JobController.class); 25 | 26 | @Autowired 27 | private Scheduler scheduler; 28 | 29 | @Autowired 30 | private SchedulerJobService schedulerJobService; 31 | 32 | // @RequestMapping("/index") 33 | // public String index(HttpServletRequest request){ 34 | // logger.info("[JobController] the url path:------------/index----------------"); 35 | // logger.info("[JobController] the method index is start......"); 36 | // List jobList = schedulerJobService.getAllScheduleJob(); 37 | // request.setAttribute("jobs",jobList); 38 | // logger.info("[JobController] the method index is end......"); 39 | // return "index"; 40 | // } 41 | 42 | /** 43 | *获取所有的任务 44 | * @return 45 | */ 46 | @RequestMapping("/getAllJobs") 47 | @ResponseBody 48 | public Object getAllJobs(){ 49 | logger.info("[JobController] the method:getAllJobs! the url path:------------/getAllJobs----------------"); 50 | List jobList = schedulerJobService.getAllScheduleJob(); 51 | logger.info("[JobController] the method:getAllJobs is execution over "); 52 | return jobList; 53 | } 54 | 55 | /** 56 | * 获取正在执行的任务列表 57 | * @return 58 | * @throws SchedulerException 59 | */ 60 | @RequestMapping("/getRunJob") 61 | @ResponseBody 62 | public Object getAllRunningJob() throws SchedulerException{ 63 | logger.info("[JobController] the method:getAllRunningJob! the url path:------------/getRunJob----------------"); 64 | List jobList = schedulerJobService.getAllRunningJob(); 65 | logger.info("[JobController] the method:getAllRunningJob is execution over "); 66 | return jobList; 67 | } 68 | 69 | /** 70 | *更新或者添加一个任务 71 | * @param scheduleJob 72 | */ 73 | @RequestMapping("/saveOrUpdate") 74 | @ResponseBody 75 | public Object addOrUpdateJob(@ModelAttribute ScheduleJob scheduleJob){ 76 | logger.info("[JobController] the method addOrUpdateJob is start URL path:/addJob, the param:{}", scheduleJob); 77 | Message message = Message.failure(); 78 | try { 79 | schedulerJobService.saveOrUpdate(scheduleJob); 80 | message = Message.success(); 81 | } catch (Exception e) { 82 | message.setMsg(e.getMessage()); 83 | logger.error("[JobController] addOrUpdateJob is failure in method:addOrUpdateJob!"); 84 | } 85 | return message; 86 | } 87 | 88 | /** 89 | *运行一个任务 90 | * @param jobName 91 | * @param jobGroup 92 | */ 93 | @RequestMapping("/runOneJob") 94 | @ResponseBody 95 | public Object runJob(String jobName, String jobGroup){ 96 | logger.info("[JobController] the url path:------------/runOneJob----------------"); 97 | Message message = Message.failure(); 98 | try { 99 | schedulerJobService.runOneJob(jobName,jobGroup); 100 | message = Message.success(); 101 | } catch (SchedulerException e) { 102 | message.setMsg(e.getMessage()); 103 | logger.error("[JobController] runOnejob is failure in method:runJob"); 104 | } 105 | return message; 106 | } 107 | 108 | /** 109 | *停止一个定时任务 110 | * @param jobName 111 | * @param jobGroup 112 | */ 113 | @RequestMapping("/pauseJob") 114 | @ResponseBody 115 | public Object pauseJob(String jobName, String jobGroup){ 116 | logger.info("[JobController] the url path:------------/runOneJob----------------"); 117 | Message message = Message.failure(); 118 | try { 119 | schedulerJobService.pauseJob(jobName,jobGroup); 120 | message = Message.success(); 121 | } catch (SchedulerException e) { 122 | message.setMsg(e.getMessage()); 123 | logger.error("[JobController] pauseJob is failure in method:pauseJob"); 124 | } 125 | return message; 126 | } 127 | 128 | /** 129 | * 删除一个定时任务 130 | * @param jobName 131 | * @param jobGroup 132 | * @return 133 | */ 134 | @RequestMapping("/deleteJob") 135 | @ResponseBody 136 | public Object deleteJob(String jobName,String jobGroup){ 137 | logger.info("[JobController] the url path:------------/runOneJob----------------"); 138 | Message message = Message.failure(); 139 | try { 140 | schedulerJobService.deleteJob(jobName,jobGroup); 141 | message = Message.success(); 142 | } catch (SchedulerException e) { 143 | message.setMsg(e.getMessage()); 144 | logger.error("[JobController] deleteJob is failre in method: deleteJob!"); 145 | } 146 | return message; 147 | } 148 | 149 | /** 150 | * 重启一个定时任务 151 | * @param jobName 152 | * @param jobGroup 153 | * @return 154 | */ 155 | @ResponseBody 156 | @RequestMapping("/resumeJob") 157 | public Object resumeJob(String jobName, String jobGroup){ 158 | logger.info("[JobController] the url path:------------/resumeJob----------------"); 159 | Message message = Message.failure(); 160 | try { 161 | schedulerJobService.resumeJob(jobName,jobGroup); 162 | message = Message.success(); 163 | } catch (SchedulerException e) { 164 | message.setMsg(e.getMessage()); 165 | logger.error("[JobController] resumeJob is failre in method: resumeJob!"); 166 | } 167 | return message; 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUARTZ 6 | 7 | 8 | 20 | 21 | 22 | 23 |
24 | 25 |
26 |
QUARTZ 任务调度动态管理系统Web UI
27 |
28 |
29 | 30 |
31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 73 | 74 | 75 | 76 | 77 |
idnamegroupbeanmethodcronsstatedescoperation
64 |
66 | 67 | 68 | 69 | 70 | 71 |
72 |
78 |
79 | 80 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | typora-root-url: pictures 3 | --- 4 | 5 | # Dynamic Quartz 6 | 7 | ​ 最近在公司实习,发现公司有一套spring+Quartz的动态任务管理系统。可以使用Web界面进行任务动态的创建、删除、停止、运行和修改。刚好最近在学习spring boot。便使用spring boot2+quartz+thymeleaf+mysql数据库实现了一个简单的动态任务管理系统。 8 | 9 | ## 项目使用方法: 10 | 11 | 使用IDEA打开该项目,并把application.properties中数据信息修改为自己的数据信息即可。同时把dynamicquartz的sql文件导入到数据中即可。项目地址:[http://localhost:8080/](http://localhost:8080/) 12 | 13 | 14 | 15 | 项目如下图所示: 16 | 17 | ![3](/3.png) 18 | 19 | ## Quartz 20 | 21 | quartz是一个java编写的开源任务调度框架其主要调度元素有: 22 | 23 | - Trigger(触发器):触发任务任务执行的时间或规则。在任务调度Quartz中,Trigger主要的触发器有:SimpleTrigger,CalendarIntervelTrigger,DailyTimeIntervalTrigger,CronTrigger 24 | - Scheduler(任务调度器):Scheduler就是任务调度控制器,需要把JobDetail和Trigger注册到schedule中,才可以执行 ;Scheduler有两个重要组件:ThreadPool和JobStore。 25 | - Job(任务):是一个接口,其中只有一个execute方法。开发者只要实现接口中的execute方法即可。 26 | - JobDetail(任务细节):Quartz执行Job时,需要新建Job实例,但不能直接操作Job类,所以通过JobDetail获得Job的名称,描述信息。 27 | 28 | 对象之间的关系图如图下图所示: 29 | 30 | ![1](/1.png) 31 | 32 | ![2](/2.png) 33 | 34 | ## Spring boot2集成quartz 35 | 36 | 1. 添加quartz依赖 37 | 38 | ```xml 39 | 40 | org.springframework.boot 41 | spring-boot-starter-quartz 42 | 43 | ``` 44 | 45 | 2. 添加spring boot2的web 、thymeleaf、依赖 46 | 47 | ```xml 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-starter-web 52 | 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-starter-websocket 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-thymeleaf 61 | 62 | ``` 63 | 64 | 其他详情依赖请具体间github项目的pom文件。 65 | 66 | 3. 相关属性的配置文件。 67 | 68 | ```yaml 69 | # 数据库连接的配置 70 | spring.datasource.druid.url=jdbc:mysql://localhost:3306/dynamicquartz?useUnicode=true&characterEncoding=utf8 71 | spring.datasource.druid.username=root 72 | spring.datasource.druid.password=2012061128 73 | spring.datasource.type=com.alibaba.druid.pool.DruidDataSource 74 | spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver 75 | spring.datasource.druid.filters=stat 76 | spring.datasource.druid.max-active=20 77 | spring.datasource.druid.initialSize=1 78 | spring.datasource.druid.max-wait=60000 79 | spring.datasource.druid.min-idle=1 80 | spring.datasource.druid.time-between-eviction-runs-millis=60000 81 | spring.datasource.druid.min-evictable-idle-time-millis=300000 82 | spring.datasource.druid.validation-query=select 'x' 83 | spring.datasource.druid.test-while-idle=true 84 | spring.datasource.druid.test-on-return=false 85 | spring.datasource.druid.test-on-borrow=false 86 | 87 | # mybatis配置 88 | mybatis.mapper-locations=classpath:mapper/*.xml 89 | mybatis.type-aliases-package=cn.bupt.zcc.dynamicquartz.model 90 | 91 | # quartz的一些属性配置 92 | spring.quartz.job-store-type=jdbc 93 | spring.quartz.properties.org.quartz.scheduler.instanceName=clusteredScheduler 94 | spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO 95 | spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX 96 | spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate 97 | spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_ 98 | #spring.quartz.properties.org.quartz.jobStore.isClustered=true 99 | #spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=10000 100 | spring.quartz.properties.org.quartz.jobStore.useProperties=false 101 | 102 | # 集成thymeleaf引擎的一些配置 103 | spring.thymeleaf.prefix=classpath:/templates/ 104 | spring.thymeleaf.check-template-location=true 105 | spring.thymeleaf.suffix=.html 106 | spring.thymeleaf.encoding=UTF-8 107 | spring.thymeleaf.servlet.content-type=text/html 108 | spring.thymeleaf.mode=HTML5 109 | spring.thymeleaf.cache=false 110 | ``` 111 | 112 | 4. 创建quartz任务工厂类:QuartzJobFactory。 113 | 114 | ```java 115 | /** 116 | * @author: Zhang Chengcheng 117 | * @create: 2018-05-31 14:38 118 | **/ 119 | @Service("quartzJobFactory") 120 | public class QuartzJobFactory extends QuartzJobBean { 121 | @Autowired 122 | QuartzService quartzService; 123 | @Override 124 | protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { 125 | ScheduleJob object = (ScheduleJob) jobExecutionContext.getMergedJobDataMap().get("scheduleJob"); 126 | if(object.getMethodName()==null || object.getMethodName().equals("")){ 127 | quartzService.executeTask(object.getBeanName()); 128 | }else { 129 | quartzService.executeTask(object.getBeanName(),object.getMethodName()); 130 | } 131 | } 132 | } 133 | ``` 134 | 135 | 这是一个任务工厂类继承了QuartzJobBean类。每动态的添加一个定时任务就是创建此类的实例。并把要执行的定时任务类的名称或者全限定类名以及要执行的方法名传入。QuartzService获取传入的spring bean的名称或者全限定类名,获取该任务类的名称并使用反射来调用method,执行任务。通过反射的方式把要执行的任务类和Job接口或者QuartzJobBean类进行解耦。任务类无需实现Job接口或者集成QuartzJobBean类。即可实现任务的动态调度了。 136 | 137 | 5. QuartzService实现类如下: 138 | 139 | ```java 140 | /** 141 | * @author: Zhang Chengcheng 142 | * @create: 2018-05-31 15:34 143 | **/ 144 | @Service("quartzService") 145 | public class QuartzServiceImpl implements QuartzService { 146 | 147 | private static final Logger logger = LoggerFactory.getLogger(QuartzServiceImpl.class); 148 | private static final String METHODNAME = "execute"; 149 | 150 | @Override 151 | public void executeTask(String beanName, String methodName) { 152 | Object object = ApplicationContextUtil.getBean(beanName); 153 | try { 154 | logger.info("[QuartzServiceImpl] 反射调beanName:{},methodName:{}法开始.........",beanName,methodName); 155 | if (beanName.contains("\\.")){ 156 | Class clazz = Class.forName(beanName); 157 | Object cronJob = ApplicationContextUtil.getBean(clazz); 158 | Method method1 = clazz.getMethod(methodName); 159 | method1.invoke(cronJob); 160 | }else { 161 | Method method = object.getClass().getMethod(methodName); 162 | method.invoke(object); 163 | } 164 | 165 | } catch (Exception e) { 166 | logger.error("[QuartzServiceImpl] method invoke error,beanName:{},methodName:{}",beanName,methodName); 167 | return; 168 | } 169 | logger.info("[QuartzServiceImpl] 反射调beanName:{},methodName:{}法结束.........",beanName,methodName); 170 | 171 | } 172 | ``` 173 | 174 | 6. ApplicationContextUtil是一个获取spring bean实例的工具类 175 | 176 | ```java 177 | /** 178 | * 179 | * @author: Zhang Chengcheng 180 | * @create: 2018-05-31 15:07 181 | **/ 182 | @Component("ApplicationContextUtil") 183 | public class ApplicationContextUtil implements ApplicationContextAware { 184 | 185 | private static ApplicationContext applicationContext; 186 | @Override 187 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 188 | ApplicationContextUtil.applicationContext = applicationContext; 189 | } 190 | public ApplicationContext getApplicationContext(){ 191 | checkApplicationContext(); 192 | return applicationContext; 193 | } 194 | 195 | public void checkApplicationContext(){ 196 | if (applicationContext==null){ 197 | throw new IllegalStateException("applicationContext 未注入,请在applicationContext.xml中定义SpringContextUtil"); 198 | } 199 | } 200 | /** 201 | *根据bean的名称去寻找一个类的实例 202 | * @param name 203 | * @param 204 | * @return 205 | */ 206 | public static T getBean(String name){ 207 | 208 | return (T) applicationContext.getBean(name); 209 | } 210 | } 211 | ``` 212 | 213 | ApplicationContextUtil类通过实现ApplicationContextAware接口,获取applicationContext上下文。从而在反射中获取任务的实例。再通过反射来执行任务。 214 | 215 | 7. 动态添加任务 216 | 217 | ```java 218 | private void addJob(ScheduleJob scheduleJob) throws Exception{ 219 | checkNotNull(scheduleJob); 220 | if (StringUtils.isBlank(scheduleJob.getCronExpression())){ 221 | throw new Exception("[SchedulerJobServiceImpl] CronExpression不能为空"); 222 | } 223 | scheduleJob.setJobStatus("NORMAL"); 224 | int id = scheduleJobInService.insertSelective(scheduleJob); 225 | logger.info("[SchedulerJobServiceImpl] the Primary key is:{}",scheduleJob.getId()); 226 | 227 | scheduleJob.setJobId(scheduleJob.getId()+""); 228 | logger.info("[SchedulerJobServiceImpl] the scheduleJob is:{}",scheduleJob); 229 | scheduleJobInService.updateByPrimaryKey(scheduleJob); 230 | JobDetail jobDetail = JobBuilder.newJob(QuartzJobFactory.class).withIdentity(scheduleJob.getJobName(),scheduleJob.getJobGroup()) 231 | .build();//创建JobDetail,job是通过QuartzJobFactory.class工厂类反射创建的。 232 | jobDetail.getJobDataMap().put("scheduleJob",scheduleJob); 233 | CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()); 234 | CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(scheduleJob.getJobName(),scheduleJob.getJobGroup()) 235 | .withSchedule(cronScheduleBuilder).build();//创建触发器 236 | scheduler.scheduleJob(jobDetail,cronTrigger);//注册jobDetail和Trigger进行任务调度。 237 | 238 | } 239 | ``` 240 | 241 | 8. 我们使用web的界面来实现任务的动态的添加。使用的是thymeleaf引擎。 242 | 243 | ![3](/3.png) 244 | 245 | 246 | 247 | 参考: 248 | 249 | [1]: https://github.com/jiwenxing/springboot-quartz "springboot-quartz" 250 | [2]: https://www.jianshu.com/p/5995937f27bc "Quartz教程" 251 | [3]: https://blog.csdn.net/u012907049/article/details/73801122 "Spring Boot集成持久化Quartz定时任务管理和界面展示" 252 | 253 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/service/impl/SchedulerJobServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.service.impl; 2 | 3 | import cn.bupt.zcc.dynamicquartz.job.QuartzJobFactory; 4 | import cn.bupt.zcc.dynamicquartz.model.ScheduleJob; 5 | import cn.bupt.zcc.dynamicquartz.service.ScheduleJobInService; 6 | import cn.bupt.zcc.dynamicquartz.service.SchedulerJobService; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.quartz.*; 9 | import org.quartz.impl.matchers.GroupMatcher; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.stereotype.Service; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.Set; 18 | 19 | /** 20 | * Created by 张城城 on 2018/6/1. 21 | */ 22 | @Service("schedulerJobService") 23 | public class SchedulerJobServiceImpl implements SchedulerJobService { 24 | 25 | private static final Logger logger = LoggerFactory.getLogger(SchedulerJobServiceImpl.class); 26 | @Autowired 27 | private Scheduler scheduler; 28 | 29 | @Autowired 30 | private ScheduleJobInService scheduleJobInService; 31 | 32 | /** 33 | * 获取所有的任务 34 | * @return 35 | */ 36 | @Override 37 | public List getAllScheduleJob() { 38 | List jobList = new ArrayList<>(); 39 | GroupMatcher matcher = GroupMatcher.anyGroup(); 40 | try { 41 | Set jobKeys = scheduler.getJobKeys(matcher); 42 | for (JobKey key : jobKeys){ 43 | List triggers = scheduler.getTriggersOfJob(key); 44 | for (Trigger trigger: triggers){ 45 | ScheduleJob scheduleJob = getScheduleJob(scheduler,key,trigger); 46 | jobList.add(scheduleJob); 47 | } 48 | } 49 | } catch (SchedulerException e) { 50 | logger.error("[SchedulerJobServiceImpl] get the jobKeys is error:{}",e); 51 | //e.printStackTrace(); 52 | } 53 | return jobList; 54 | } 55 | 56 | /** 57 | * 获取所有运行中的任务 58 | * @return 59 | * @throws SchedulerException 60 | */ 61 | @Override 62 | public List getAllRunningJob() throws SchedulerException { 63 | 64 | List executionJobList = scheduler.getCurrentlyExecutingJobs(); 65 | List jobList = new ArrayList<>(); 66 | for (JobExecutionContext jobExecutionContext: executionJobList){ 67 | JobDetail jobDetail = jobExecutionContext.getJobDetail(); 68 | JobKey jobKey = jobDetail.getKey(); 69 | Trigger trigger = jobExecutionContext.getTrigger(); 70 | ScheduleJob scheduleJob = getScheduleJob(scheduler,jobKey,trigger); 71 | jobList.add(scheduleJob); 72 | } 73 | return jobList; 74 | } 75 | 76 | /** 77 | * 更新新的任务或者添加一个新的任务 78 | * @param scheduleJob 79 | * @throws Exception 80 | */ 81 | @Override 82 | public void saveOrUpdate(ScheduleJob scheduleJob) throws Exception{ 83 | TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(),scheduleJob.getJobGroup()); 84 | CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); 85 | if (cronTrigger==null){ 86 | addJob(scheduleJob); 87 | }else { 88 | updateJobCronSchedule(scheduleJob); 89 | } 90 | } 91 | 92 | /** 93 | * 停止运行任务 94 | * @param jobName 95 | * @param jobGroup 96 | * @throws SchedulerException 97 | */ 98 | public void pauseJob(String jobName, String jobGroup) throws SchedulerException{ 99 | JobKey jobKey = JobKey.jobKey(jobName,jobGroup); 100 | ScheduleJob scheduleJob = scheduleJobInService.selectByJobNameAngJobGroup(jobName,jobGroup); 101 | scheduleJob.setJobStatus("PAUSED"); 102 | scheduleJobInService.updateByPrimaryKey(scheduleJob); 103 | scheduler.pauseJob(jobKey); 104 | } 105 | 106 | /** 107 | * 删除一个任务 108 | * @param jobName 109 | * @param jobGroup 110 | * @throws SchedulerException 111 | */ 112 | public void deleteJob(String jobName,String jobGroup) throws SchedulerException{ 113 | JobKey jobKey = JobKey.jobKey(jobName, jobGroup); 114 | scheduleJobInService.deleteByJobNameAndJobGroup(jobName,jobGroup); 115 | scheduler.deleteJob(jobKey); 116 | } 117 | 118 | /** 119 | * 运行一个任务 120 | * @param jobName 121 | * @param jobGroup 122 | * @throws SchedulerException 123 | */ 124 | public void runOneJob(String jobName, String jobGroup) throws SchedulerException{ 125 | JobKey jobKey = JobKey.jobKey(jobName, jobGroup); 126 | ScheduleJob scheduleJob = scheduleJobInService.selectByJobNameAngJobGroup(jobName, jobGroup); 127 | scheduleJob.setJobStatus("NORMAL"); 128 | scheduleJobInService.updateByPrimaryKey(scheduleJob); 129 | scheduler.triggerJob(jobKey); 130 | } 131 | 132 | /** 133 | * 重启一个任务 134 | * @param jobName 135 | * @param jobGroup 136 | * @throws SchedulerException 137 | */ 138 | public void resumeJob(String jobName, String jobGroup) throws SchedulerException{ 139 | JobKey jobKey = JobKey.jobKey(jobName,jobGroup); 140 | ScheduleJob scheduleJob = scheduleJobInService.selectByJobNameAngJobGroup(jobName,jobGroup); 141 | scheduleJob.setJobStatus("PAUSED"); 142 | scheduler.resumeJob(jobKey); 143 | } 144 | 145 | 146 | /** 147 | * 添加任务 148 | * @param scheduleJob 149 | * @throws Exception 150 | */ 151 | private void addJob(ScheduleJob scheduleJob) throws Exception{ 152 | checkNotNull(scheduleJob); 153 | if (StringUtils.isBlank(scheduleJob.getCronExpression())){ 154 | throw new Exception("[SchedulerJobServiceImpl] CronExpression不能为空"); 155 | } 156 | scheduleJob.setJobStatus("NORMAL"); 157 | int id = scheduleJobInService.insertSelective(scheduleJob); 158 | logger.info("[SchedulerJobServiceImpl] the Primary key is:{}",scheduleJob.getId()); 159 | 160 | scheduleJob.setJobId(scheduleJob.getId()+""); 161 | logger.info("[SchedulerJobServiceImpl] the scheduleJob is:{}",scheduleJob); 162 | scheduleJobInService.updateByPrimaryKey(scheduleJob); 163 | JobDetail jobDetail = JobBuilder.newJob(QuartzJobFactory.class).withIdentity(scheduleJob.getJobName(),scheduleJob.getJobGroup()) 164 | .build(); 165 | jobDetail.getJobDataMap().put("scheduleJob",scheduleJob); 166 | CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()); 167 | CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(scheduleJob.getJobName(),scheduleJob.getJobGroup()) 168 | .withSchedule(cronScheduleBuilder).build(); 169 | scheduler.scheduleJob(jobDetail,cronTrigger); 170 | 171 | } 172 | 173 | /** 174 | * 更新一个任务 175 | * @param scheduleJob 176 | * @throws Exception 177 | */ 178 | private void updateJobCronSchedule(ScheduleJob scheduleJob) throws Exception{ 179 | checkNotNull(scheduleJob); 180 | if (StringUtils.isBlank(scheduleJob.getCronExpression())){ 181 | throw new Exception("[SchedulerJobServiceImpl] CronExpression不能为空"); 182 | } 183 | TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(),scheduleJob.getJobGroup()); 184 | CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); 185 | CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()); 186 | cronTrigger = cronTrigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build(); 187 | JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(),scheduleJob.getJobGroup()); 188 | JobDetail jobDetail=scheduler.getJobDetail(jobKey); 189 | jobDetail.getJobDataMap().put("scheduleJob",scheduleJob); 190 | scheduler.rescheduleJob(triggerKey,cronTrigger); 191 | scheduleJobInService.updateByPrimaryKey(scheduleJob); 192 | 193 | } 194 | 195 | 196 | /** 197 | * 判断一个任务是否为空 198 | * @param scheduleJob 199 | */ 200 | @Override 201 | public void checkNotNull(ScheduleJob scheduleJob) { 202 | if (scheduleJob==null){ 203 | throw new IllegalStateException("scheduleJob is null,Please check it"); 204 | } 205 | if (scheduleJob.getJobName()==null || scheduleJob.getJobName().equals("")){ 206 | throw new IllegalStateException("the jobName of scheduleJob is null,Please check it"); 207 | } 208 | if (scheduleJob.getJobGroup()==null || scheduleJob.getJobGroup().equals("")){ 209 | throw new IllegalStateException("the jobGroup of scheduleJob is null,Please check it"); 210 | } 211 | if (scheduleJob.getBeanName()==null || scheduleJob.getBeanName().equals("")){ 212 | throw new IllegalStateException("the BeanName of scheduleJob is null,Please check it"); 213 | } 214 | 215 | 216 | } 217 | 218 | 219 | 220 | private ScheduleJob getScheduleJob(Scheduler schedule, JobKey jobKey, Trigger trigger){ 221 | ScheduleJob scheduleJob = new ScheduleJob(); 222 | try { 223 | JobDetail jobDetail = scheduler.getJobDetail(jobKey); 224 | scheduleJob = (ScheduleJob)jobDetail.getJobDataMap().get("scheduleJob"); 225 | Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey()); 226 | scheduleJob.setJobStatus(triggerState.name()); 227 | scheduleJob.setJobName(jobKey.getName()); 228 | scheduleJob.setJobGroup(jobKey.getGroup()); 229 | if (trigger instanceof CronTrigger){ 230 | CronTrigger cronTrigger = (CronTrigger) trigger; 231 | scheduleJob.setCronExpression(cronTrigger.getCronExpression()); 232 | } 233 | 234 | } catch (Exception e) { 235 | logger.error("[SchedulerJobServiceImpl] method getScheduleJob get JobDetail error:{}",e); 236 | } 237 | return scheduleJob; 238 | } 239 | 240 | } 241 | -------------------------------------------------------------------------------- /src/main/resources/mapper/ScheduleJobMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | and ${criterion.condition} 24 | 25 | 26 | and ${criterion.condition} #{criterion.value} 27 | 28 | 29 | and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} 30 | 31 | 32 | and ${criterion.condition} 33 | 34 | #{listItem} 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | and ${criterion.condition} 53 | 54 | 55 | and ${criterion.condition} #{criterion.value} 56 | 57 | 58 | and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} 59 | 60 | 61 | and ${criterion.condition} 62 | 63 | #{listItem} 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | id, job_id, job_name, job_status, job_Group, cron_Expression, description, bean_name, 75 | method_name 76 | 77 | 92 | 98 | 99 | delete from schedule_job 100 | where id = #{id,jdbcType=INTEGER} 101 | 102 | 103 | delete from schedule_job 104 | 105 | 106 | 107 | 108 | 109 | insert into schedule_job (id, job_id, job_name, 110 | job_status, job_Group, cron_Expression, 111 | description, bean_name, method_name 112 | ) 113 | values (#{id,jdbcType=INTEGER}, #{jobId,jdbcType=VARCHAR}, #{jobName,jdbcType=VARCHAR}, 114 | #{jobStatus,jdbcType=VARCHAR}, #{jobGroup,jdbcType=VARCHAR}, #{cronExpression,jdbcType=VARCHAR}, 115 | #{description,jdbcType=VARCHAR}, #{beanName,jdbcType=VARCHAR}, #{methodName,jdbcType=VARCHAR} 116 | ) 117 | 118 | 119 | insert into schedule_job 120 | 121 | 122 | id, 123 | 124 | 125 | job_id, 126 | 127 | 128 | job_name, 129 | 130 | 131 | job_status, 132 | 133 | 134 | job_Group, 135 | 136 | 137 | cron_Expression, 138 | 139 | 140 | description, 141 | 142 | 143 | bean_name, 144 | 145 | 146 | method_name, 147 | 148 | 149 | 150 | 151 | #{id,jdbcType=INTEGER}, 152 | 153 | 154 | #{jobId,jdbcType=VARCHAR}, 155 | 156 | 157 | #{jobName,jdbcType=VARCHAR}, 158 | 159 | 160 | #{jobStatus,jdbcType=VARCHAR}, 161 | 162 | 163 | #{jobGroup,jdbcType=VARCHAR}, 164 | 165 | 166 | #{cronExpression,jdbcType=VARCHAR}, 167 | 168 | 169 | #{description,jdbcType=VARCHAR}, 170 | 171 | 172 | #{beanName,jdbcType=VARCHAR}, 173 | 174 | 175 | #{methodName,jdbcType=VARCHAR}, 176 | 177 | 178 | 179 | 185 | 186 | update schedule_job 187 | 188 | 189 | id = #{record.id,jdbcType=INTEGER}, 190 | 191 | 192 | job_id = #{record.jobId,jdbcType=VARCHAR}, 193 | 194 | 195 | job_name = #{record.jobName,jdbcType=VARCHAR}, 196 | 197 | 198 | job_status = #{record.jobStatus,jdbcType=VARCHAR}, 199 | 200 | 201 | job_Group = #{record.jobGroup,jdbcType=VARCHAR}, 202 | 203 | 204 | cron_Expression = #{record.cronExpression,jdbcType=VARCHAR}, 205 | 206 | 207 | description = #{record.description,jdbcType=VARCHAR}, 208 | 209 | 210 | bean_name = #{record.beanName,jdbcType=VARCHAR}, 211 | 212 | 213 | method_name = #{record.methodName,jdbcType=VARCHAR}, 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | update schedule_job 222 | set id = #{record.id,jdbcType=INTEGER}, 223 | job_id = #{record.jobId,jdbcType=VARCHAR}, 224 | job_name = #{record.jobName,jdbcType=VARCHAR}, 225 | job_status = #{record.jobStatus,jdbcType=VARCHAR}, 226 | job_Group = #{record.jobGroup,jdbcType=VARCHAR}, 227 | cron_Expression = #{record.cronExpression,jdbcType=VARCHAR}, 228 | description = #{record.description,jdbcType=VARCHAR}, 229 | bean_name = #{record.beanName,jdbcType=VARCHAR}, 230 | method_name = #{record.methodName,jdbcType=VARCHAR} 231 | 232 | 233 | 234 | 235 | 236 | update schedule_job 237 | 238 | 239 | job_id = #{jobId,jdbcType=VARCHAR}, 240 | 241 | 242 | job_name = #{jobName,jdbcType=VARCHAR}, 243 | 244 | 245 | job_status = #{jobStatus,jdbcType=VARCHAR}, 246 | 247 | 248 | job_Group = #{jobGroup,jdbcType=VARCHAR}, 249 | 250 | 251 | cron_Expression = #{cronExpression,jdbcType=VARCHAR}, 252 | 253 | 254 | description = #{description,jdbcType=VARCHAR}, 255 | 256 | 257 | bean_name = #{beanName,jdbcType=VARCHAR}, 258 | 259 | 260 | method_name = #{methodName,jdbcType=VARCHAR}, 261 | 262 | 263 | where id = #{id,jdbcType=INTEGER} 264 | 265 | 266 | update schedule_job 267 | set job_id = #{jobId,jdbcType=VARCHAR}, 268 | job_name = #{jobName,jdbcType=VARCHAR}, 269 | job_status = #{jobStatus,jdbcType=VARCHAR}, 270 | job_Group = #{jobGroup,jdbcType=VARCHAR}, 271 | cron_Expression = #{cronExpression,jdbcType=VARCHAR}, 272 | description = #{description,jdbcType=VARCHAR}, 273 | bean_name = #{beanName,jdbcType=VARCHAR}, 274 | method_name = #{methodName,jdbcType=VARCHAR} 275 | where id = #{id,jdbcType=INTEGER} 276 | 277 | -------------------------------------------------------------------------------- /dynamicquartz.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : demo 5 | Source Server Version : 50528 6 | Source Host : localhost:3306 7 | Source Database : dynamicquartz 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 50528 11 | File Encoding : 65001 12 | 13 | Date: 2018-06-14 21:49:19 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for qrtz_blob_triggers 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `qrtz_blob_triggers`; 22 | CREATE TABLE `qrtz_blob_triggers` ( 23 | `SCHED_NAME` varchar(120) NOT NULL, 24 | `TRIGGER_NAME` varchar(200) NOT NULL, 25 | `TRIGGER_GROUP` varchar(200) NOT NULL, 26 | `BLOB_DATA` blob, 27 | PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`), 28 | CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) 29 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 30 | 31 | -- ---------------------------- 32 | -- Records of qrtz_blob_triggers 33 | -- ---------------------------- 34 | 35 | -- ---------------------------- 36 | -- Table structure for qrtz_calendars 37 | -- ---------------------------- 38 | DROP TABLE IF EXISTS `qrtz_calendars`; 39 | CREATE TABLE `qrtz_calendars` ( 40 | `SCHED_NAME` varchar(120) NOT NULL, 41 | `CALENDAR_NAME` varchar(200) NOT NULL, 42 | `CALENDAR` blob NOT NULL, 43 | PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`) 44 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 45 | 46 | -- ---------------------------- 47 | -- Records of qrtz_calendars 48 | -- ---------------------------- 49 | 50 | -- ---------------------------- 51 | -- Table structure for qrtz_cron_triggers 52 | -- ---------------------------- 53 | DROP TABLE IF EXISTS `qrtz_cron_triggers`; 54 | CREATE TABLE `qrtz_cron_triggers` ( 55 | `SCHED_NAME` varchar(120) NOT NULL, 56 | `TRIGGER_NAME` varchar(200) NOT NULL, 57 | `TRIGGER_GROUP` varchar(200) NOT NULL, 58 | `CRON_EXPRESSION` varchar(200) NOT NULL, 59 | `TIME_ZONE_ID` varchar(80) DEFAULT NULL, 60 | PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`), 61 | CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) 62 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 63 | 64 | -- ---------------------------- 65 | -- Records of qrtz_cron_triggers 66 | -- ---------------------------- 67 | INSERT INTO `qrtz_cron_triggers` VALUES ('quartzScheduler', 'hello', 'hello', '0/55 * * * * ?', 'Asia/Shanghai'); 68 | INSERT INTO `qrtz_cron_triggers` VALUES ('quartzScheduler', 'sweetzcc', 'sweetzcc', '0/30 * * * * ?', 'Asia/Shanghai'); 69 | INSERT INTO `qrtz_cron_triggers` VALUES ('quartzScheduler', 'test', 'test', '0/30 * * * * ?', 'Asia/Shanghai'); 70 | 71 | -- ---------------------------- 72 | -- Table structure for qrtz_fired_triggers 73 | -- ---------------------------- 74 | DROP TABLE IF EXISTS `qrtz_fired_triggers`; 75 | CREATE TABLE `qrtz_fired_triggers` ( 76 | `SCHED_NAME` varchar(120) NOT NULL, 77 | `ENTRY_ID` varchar(95) NOT NULL, 78 | `TRIGGER_NAME` varchar(200) NOT NULL, 79 | `TRIGGER_GROUP` varchar(200) NOT NULL, 80 | `INSTANCE_NAME` varchar(200) NOT NULL, 81 | `FIRED_TIME` bigint(13) NOT NULL, 82 | `SCHED_TIME` bigint(13) NOT NULL, 83 | `PRIORITY` int(11) NOT NULL, 84 | `STATE` varchar(16) NOT NULL, 85 | `JOB_NAME` varchar(200) DEFAULT NULL, 86 | `JOB_GROUP` varchar(200) DEFAULT NULL, 87 | `IS_NONCONCURRENT` varchar(1) DEFAULT NULL, 88 | `REQUESTS_RECOVERY` varchar(1) DEFAULT NULL, 89 | PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`) 90 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 91 | 92 | -- ---------------------------- 93 | -- Records of qrtz_fired_triggers 94 | -- ---------------------------- 95 | INSERT INTO `qrtz_fired_triggers` VALUES ('quartzScheduler', 'NON_CLUSTERED1528009888206', 'test', 'test', 'NON_CLUSTERED', '1528010880052', '1528010910000', '5', 'ACQUIRED', null, null, '0', '0'); 96 | 97 | -- ---------------------------- 98 | -- Table structure for qrtz_job_details 99 | -- ---------------------------- 100 | DROP TABLE IF EXISTS `qrtz_job_details`; 101 | CREATE TABLE `qrtz_job_details` ( 102 | `SCHED_NAME` varchar(120) NOT NULL, 103 | `JOB_NAME` varchar(200) NOT NULL, 104 | `JOB_GROUP` varchar(200) NOT NULL, 105 | `DESCRIPTION` varchar(250) DEFAULT NULL, 106 | `JOB_CLASS_NAME` varchar(250) NOT NULL, 107 | `IS_DURABLE` varchar(1) NOT NULL, 108 | `IS_NONCONCURRENT` varchar(1) NOT NULL, 109 | `IS_UPDATE_DATA` varchar(1) NOT NULL, 110 | `REQUESTS_RECOVERY` varchar(1) NOT NULL, 111 | `JOB_DATA` blob, 112 | PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`) 113 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 114 | 115 | -- ---------------------------- 116 | -- Records of qrtz_job_details 117 | -- ---------------------------- 118 | INSERT INTO `qrtz_job_details` VALUES ('quartzScheduler', 'hello', 'hello', null, 'cn.bupt.zcc.dynamicquartz.job.QuartzJobFactory', '0', '0', '0', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C7708000000100000000174000B7363686564756C654A6F627372002B636E2E627570742E7A63632E64796E616D696371756172747A2E6D6F64656C2E5363686564756C654A6F6200000000000000010200094C00086265616E4E616D657400124C6A6176612F6C616E672F537472696E673B4C000E63726F6E45787072657373696F6E71007E00094C000B6465736372697074696F6E71007E00094C000269647400134C6A6176612F6C616E672F496E74656765723B4C00086A6F6247726F757071007E00094C00056A6F62496471007E00094C00076A6F624E616D6571007E00094C00096A6F6253746174757371007E00094C000A6D6574686F644E616D6571007E0009787074000B7465737443726F6E4A6F6274000E302F3535202A202A202A202A203F74000474657374737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000974000568656C6C6F7400013974000568656C6C6F7400064E4F524D414C740007657865637574657800); 119 | INSERT INTO `qrtz_job_details` VALUES ('quartzScheduler', 'sweetzcc', 'sweetzcc', null, 'cn.bupt.zcc.dynamicquartz.job.QuartzJobFactory', '0', '0', '0', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C7708000000100000000174000B7363686564756C654A6F627372002B636E2E627570742E7A63632E64796E616D696371756172747A2E6D6F64656C2E5363686564756C654A6F6200000000000000010200094C00086265616E4E616D657400124C6A6176612F6C616E672F537472696E673B4C000E63726F6E45787072657373696F6E71007E00094C000B6465736372697074696F6E71007E00094C000269647400134C6A6176612F6C616E672F496E74656765723B4C00086A6F6247726F757071007E00094C00056A6F62496471007E00094C00076A6F624E616D6571007E00094C00096A6F6253746174757371007E00094C000A6D6574686F644E616D6571007E0009787074000C68656C6C6F43726F6E4A6F6274000E302F3330202A202A202A202A203F74000F61726520796F75207265616479203F737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000874000873776565747A63637400013874000873776565747A63637400064E4F524D414C740007657865637574657800); 120 | INSERT INTO `qrtz_job_details` VALUES ('quartzScheduler', 'test', 'test', null, 'cn.bupt.zcc.dynamicquartz.job.QuartzJobFactory', '0', '0', '0', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C7708000000100000000174000B7363686564756C654A6F627372002B636E2E627570742E7A63632E64796E616D696371756172747A2E6D6F64656C2E5363686564756C654A6F6200000000000000010200094C00086265616E4E616D657400124C6A6176612F6C616E672F537472696E673B4C000E63726F6E45787072657373696F6E71007E00094C000B6465736372697074696F6E71007E00094C000269647400134C6A6176612F6C616E672F496E74656765723B4C00086A6F6247726F757071007E00094C00056A6F62496471007E00094C00076A6F624E616D6571007E00094C00096A6F6253746174757371007E00094C000A6D6574686F644E616D6571007E0009787074000B7465737443726F6E4A6F6274000E302F3330202A202A202A202A203F74000568656C6C6F737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000A740004746573747400023130740004746573747400064E4F524D414C740007657865637574657800); 121 | 122 | -- ---------------------------- 123 | -- Table structure for qrtz_locks 124 | -- ---------------------------- 125 | DROP TABLE IF EXISTS `qrtz_locks`; 126 | CREATE TABLE `qrtz_locks` ( 127 | `SCHED_NAME` varchar(120) NOT NULL, 128 | `LOCK_NAME` varchar(40) NOT NULL, 129 | PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`) 130 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 131 | 132 | -- ---------------------------- 133 | -- Records of qrtz_locks 134 | -- ---------------------------- 135 | INSERT INTO `qrtz_locks` VALUES ('quartzScheduler', 'TRIGGER_ACCESS'); 136 | 137 | -- ---------------------------- 138 | -- Table structure for qrtz_paused_trigger_grps 139 | -- ---------------------------- 140 | DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`; 141 | CREATE TABLE `qrtz_paused_trigger_grps` ( 142 | `SCHED_NAME` varchar(120) NOT NULL, 143 | `TRIGGER_GROUP` varchar(200) NOT NULL, 144 | PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`) 145 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 146 | 147 | -- ---------------------------- 148 | -- Records of qrtz_paused_trigger_grps 149 | -- ---------------------------- 150 | 151 | -- ---------------------------- 152 | -- Table structure for qrtz_scheduler_state 153 | -- ---------------------------- 154 | DROP TABLE IF EXISTS `qrtz_scheduler_state`; 155 | CREATE TABLE `qrtz_scheduler_state` ( 156 | `SCHED_NAME` varchar(120) NOT NULL, 157 | `INSTANCE_NAME` varchar(200) NOT NULL, 158 | `LAST_CHECKIN_TIME` bigint(13) NOT NULL, 159 | `CHECKIN_INTERVAL` bigint(13) NOT NULL, 160 | PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`) 161 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 162 | 163 | -- ---------------------------- 164 | -- Records of qrtz_scheduler_state 165 | -- ---------------------------- 166 | 167 | -- ---------------------------- 168 | -- Table structure for qrtz_simple_triggers 169 | -- ---------------------------- 170 | DROP TABLE IF EXISTS `qrtz_simple_triggers`; 171 | CREATE TABLE `qrtz_simple_triggers` ( 172 | `SCHED_NAME` varchar(120) NOT NULL, 173 | `TRIGGER_NAME` varchar(200) NOT NULL, 174 | `TRIGGER_GROUP` varchar(200) NOT NULL, 175 | `REPEAT_COUNT` bigint(7) NOT NULL, 176 | `REPEAT_INTERVAL` bigint(12) NOT NULL, 177 | `TIMES_TRIGGERED` bigint(10) NOT NULL, 178 | PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`), 179 | CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) 180 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 181 | 182 | -- ---------------------------- 183 | -- Records of qrtz_simple_triggers 184 | -- ---------------------------- 185 | 186 | -- ---------------------------- 187 | -- Table structure for qrtz_simprop_triggers 188 | -- ---------------------------- 189 | DROP TABLE IF EXISTS `qrtz_simprop_triggers`; 190 | CREATE TABLE `qrtz_simprop_triggers` ( 191 | `SCHED_NAME` varchar(120) NOT NULL, 192 | `TRIGGER_NAME` varchar(200) NOT NULL, 193 | `TRIGGER_GROUP` varchar(200) NOT NULL, 194 | `STR_PROP_1` varchar(512) DEFAULT NULL, 195 | `STR_PROP_2` varchar(512) DEFAULT NULL, 196 | `STR_PROP_3` varchar(512) DEFAULT NULL, 197 | `INT_PROP_1` int(11) DEFAULT NULL, 198 | `INT_PROP_2` int(11) DEFAULT NULL, 199 | `LONG_PROP_1` bigint(20) DEFAULT NULL, 200 | `LONG_PROP_2` bigint(20) DEFAULT NULL, 201 | `DEC_PROP_1` decimal(13,4) DEFAULT NULL, 202 | `DEC_PROP_2` decimal(13,4) DEFAULT NULL, 203 | `BOOL_PROP_1` varchar(1) DEFAULT NULL, 204 | `BOOL_PROP_2` varchar(1) DEFAULT NULL, 205 | PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`), 206 | CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) 207 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 208 | 209 | -- ---------------------------- 210 | -- Records of qrtz_simprop_triggers 211 | -- ---------------------------- 212 | 213 | -- ---------------------------- 214 | -- Table structure for qrtz_triggers 215 | -- ---------------------------- 216 | DROP TABLE IF EXISTS `qrtz_triggers`; 217 | CREATE TABLE `qrtz_triggers` ( 218 | `SCHED_NAME` varchar(120) NOT NULL, 219 | `TRIGGER_NAME` varchar(200) NOT NULL, 220 | `TRIGGER_GROUP` varchar(200) NOT NULL, 221 | `JOB_NAME` varchar(200) NOT NULL, 222 | `JOB_GROUP` varchar(200) NOT NULL, 223 | `DESCRIPTION` varchar(250) DEFAULT NULL, 224 | `NEXT_FIRE_TIME` bigint(13) DEFAULT NULL, 225 | `PREV_FIRE_TIME` bigint(13) DEFAULT NULL, 226 | `PRIORITY` int(11) DEFAULT NULL, 227 | `TRIGGER_STATE` varchar(16) NOT NULL, 228 | `TRIGGER_TYPE` varchar(8) NOT NULL, 229 | `START_TIME` bigint(13) NOT NULL, 230 | `END_TIME` bigint(13) DEFAULT NULL, 231 | `CALENDAR_NAME` varchar(200) DEFAULT NULL, 232 | `MISFIRE_INSTR` smallint(2) DEFAULT NULL, 233 | `JOB_DATA` blob, 234 | PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`), 235 | KEY `SCHED_NAME` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`), 236 | CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `qrtz_job_details` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) 237 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 238 | 239 | -- ---------------------------- 240 | -- Records of qrtz_triggers 241 | -- ---------------------------- 242 | INSERT INTO `qrtz_triggers` VALUES ('quartzScheduler', 'hello', 'hello', 'hello', 'hello', null, '1528010035000', '1528009980000', '5', 'PAUSED', 'CRON', '1528009817000', '0', null, '0', ''); 243 | INSERT INTO `qrtz_triggers` VALUES ('quartzScheduler', 'sweetzcc', 'sweetzcc', 'sweetzcc', 'sweetzcc', null, '1528010910000', '1528010880000', '5', 'WAITING', 'CRON', '1527997003000', '0', null, '0', ''); 244 | INSERT INTO `qrtz_triggers` VALUES ('quartzScheduler', 'test', 'test', 'test', 'test', null, '1528010910000', '1528010880000', '5', 'ACQUIRED', 'CRON', '1528009974000', '0', null, '0', ''); 245 | 246 | -- ---------------------------- 247 | -- Table structure for schedule_job 248 | -- ---------------------------- 249 | DROP TABLE IF EXISTS `schedule_job`; 250 | CREATE TABLE `schedule_job` ( 251 | `id` int(11) NOT NULL AUTO_INCREMENT, 252 | `job_id` varchar(255) DEFAULT NULL, 253 | `job_name` varchar(255) DEFAULT NULL, 254 | `job_status` varchar(255) DEFAULT NULL, 255 | `job_Group` varchar(255) DEFAULT NULL, 256 | `cron_Expression` varchar(255) DEFAULT NULL, 257 | `description` varchar(255) DEFAULT NULL, 258 | `bean_name` varchar(255) DEFAULT NULL, 259 | `method_name` varchar(255) DEFAULT NULL, 260 | PRIMARY KEY (`id`) 261 | ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8; 262 | 263 | -- ---------------------------- 264 | -- Records of schedule_job 265 | -- ---------------------------- 266 | INSERT INTO `schedule_job` VALUES ('8', '8', 'sweetzcc', 'PAUSED', 'sweetzcc', '0/30 * * * * ?', 'are you ready ?', 'helloCronJob', 'execute'); 267 | INSERT INTO `schedule_job` VALUES ('9', '9', 'hello', 'PAUSED', 'hello', '0/55 * * * * ?', 'test', 'testCronJob', 'execute'); 268 | INSERT INTO `schedule_job` VALUES ('10', '10', 'test', 'NORMAL', 'test', '0/30 * * * * ?', 'hello', 'testCronJob', 'execute'); 269 | -------------------------------------------------------------------------------- /src/main/java/cn/bupt/zcc/dynamicquartz/model/ScheduleJobExample.java: -------------------------------------------------------------------------------- 1 | package cn.bupt.zcc.dynamicquartz.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class ScheduleJobExample { 7 | protected String orderByClause; 8 | 9 | protected boolean distinct; 10 | 11 | protected List oredCriteria; 12 | 13 | public ScheduleJobExample() { 14 | oredCriteria = new ArrayList(); 15 | } 16 | 17 | public void setOrderByClause(String orderByClause) { 18 | this.orderByClause = orderByClause; 19 | } 20 | 21 | public String getOrderByClause() { 22 | return orderByClause; 23 | } 24 | 25 | public void setDistinct(boolean distinct) { 26 | this.distinct = distinct; 27 | } 28 | 29 | public boolean isDistinct() { 30 | return distinct; 31 | } 32 | 33 | public List getOredCriteria() { 34 | return oredCriteria; 35 | } 36 | 37 | public void or(Criteria criteria) { 38 | oredCriteria.add(criteria); 39 | } 40 | 41 | public Criteria or() { 42 | Criteria criteria = createCriteriaInternal(); 43 | oredCriteria.add(criteria); 44 | return criteria; 45 | } 46 | 47 | public Criteria createCriteria() { 48 | Criteria criteria = createCriteriaInternal(); 49 | if (oredCriteria.size() == 0) { 50 | oredCriteria.add(criteria); 51 | } 52 | return criteria; 53 | } 54 | 55 | protected Criteria createCriteriaInternal() { 56 | Criteria criteria = new Criteria(); 57 | return criteria; 58 | } 59 | 60 | public void clear() { 61 | oredCriteria.clear(); 62 | orderByClause = null; 63 | distinct = false; 64 | } 65 | 66 | protected abstract static class GeneratedCriteria { 67 | protected List criteria; 68 | 69 | protected GeneratedCriteria() { 70 | super(); 71 | criteria = new ArrayList(); 72 | } 73 | 74 | public boolean isValid() { 75 | return criteria.size() > 0; 76 | } 77 | 78 | public List getAllCriteria() { 79 | return criteria; 80 | } 81 | 82 | public List getCriteria() { 83 | return criteria; 84 | } 85 | 86 | protected void addCriterion(String condition) { 87 | if (condition == null) { 88 | throw new RuntimeException("Value for condition cannot be null"); 89 | } 90 | criteria.add(new Criterion(condition)); 91 | } 92 | 93 | protected void addCriterion(String condition, Object value, String property) { 94 | if (value == null) { 95 | throw new RuntimeException("Value for " + property + " cannot be null"); 96 | } 97 | criteria.add(new Criterion(condition, value)); 98 | } 99 | 100 | protected void addCriterion(String condition, Object value1, Object value2, String property) { 101 | if (value1 == null || value2 == null) { 102 | throw new RuntimeException("Between values for " + property + " cannot be null"); 103 | } 104 | criteria.add(new Criterion(condition, value1, value2)); 105 | } 106 | 107 | public Criteria andIdIsNull() { 108 | addCriterion("id is null"); 109 | return (Criteria) this; 110 | } 111 | 112 | public Criteria andIdIsNotNull() { 113 | addCriterion("id is not null"); 114 | return (Criteria) this; 115 | } 116 | 117 | public Criteria andIdEqualTo(Integer value) { 118 | addCriterion("id =", value, "id"); 119 | return (Criteria) this; 120 | } 121 | 122 | public Criteria andIdNotEqualTo(Integer value) { 123 | addCriterion("id <>", value, "id"); 124 | return (Criteria) this; 125 | } 126 | 127 | public Criteria andIdGreaterThan(Integer value) { 128 | addCriterion("id >", value, "id"); 129 | return (Criteria) this; 130 | } 131 | 132 | public Criteria andIdGreaterThanOrEqualTo(Integer value) { 133 | addCriterion("id >=", value, "id"); 134 | return (Criteria) this; 135 | } 136 | 137 | public Criteria andIdLessThan(Integer value) { 138 | addCriterion("id <", value, "id"); 139 | return (Criteria) this; 140 | } 141 | 142 | public Criteria andIdLessThanOrEqualTo(Integer value) { 143 | addCriterion("id <=", value, "id"); 144 | return (Criteria) this; 145 | } 146 | 147 | public Criteria andIdIn(List values) { 148 | addCriterion("id in", values, "id"); 149 | return (Criteria) this; 150 | } 151 | 152 | public Criteria andIdNotIn(List values) { 153 | addCriterion("id not in", values, "id"); 154 | return (Criteria) this; 155 | } 156 | 157 | public Criteria andIdBetween(Integer value1, Integer value2) { 158 | addCriterion("id between", value1, value2, "id"); 159 | return (Criteria) this; 160 | } 161 | 162 | public Criteria andIdNotBetween(Integer value1, Integer value2) { 163 | addCriterion("id not between", value1, value2, "id"); 164 | return (Criteria) this; 165 | } 166 | 167 | public Criteria andJobIdIsNull() { 168 | addCriterion("job_id is null"); 169 | return (Criteria) this; 170 | } 171 | 172 | public Criteria andJobIdIsNotNull() { 173 | addCriterion("job_id is not null"); 174 | return (Criteria) this; 175 | } 176 | 177 | public Criteria andJobIdEqualTo(String value) { 178 | addCriterion("job_id =", value, "jobId"); 179 | return (Criteria) this; 180 | } 181 | 182 | public Criteria andJobIdNotEqualTo(String value) { 183 | addCriterion("job_id <>", value, "jobId"); 184 | return (Criteria) this; 185 | } 186 | 187 | public Criteria andJobIdGreaterThan(String value) { 188 | addCriterion("job_id >", value, "jobId"); 189 | return (Criteria) this; 190 | } 191 | 192 | public Criteria andJobIdGreaterThanOrEqualTo(String value) { 193 | addCriterion("job_id >=", value, "jobId"); 194 | return (Criteria) this; 195 | } 196 | 197 | public Criteria andJobIdLessThan(String value) { 198 | addCriterion("job_id <", value, "jobId"); 199 | return (Criteria) this; 200 | } 201 | 202 | public Criteria andJobIdLessThanOrEqualTo(String value) { 203 | addCriterion("job_id <=", value, "jobId"); 204 | return (Criteria) this; 205 | } 206 | 207 | public Criteria andJobIdLike(String value) { 208 | addCriterion("job_id like", value, "jobId"); 209 | return (Criteria) this; 210 | } 211 | 212 | public Criteria andJobIdNotLike(String value) { 213 | addCriterion("job_id not like", value, "jobId"); 214 | return (Criteria) this; 215 | } 216 | 217 | public Criteria andJobIdIn(List values) { 218 | addCriterion("job_id in", values, "jobId"); 219 | return (Criteria) this; 220 | } 221 | 222 | public Criteria andJobIdNotIn(List values) { 223 | addCriterion("job_id not in", values, "jobId"); 224 | return (Criteria) this; 225 | } 226 | 227 | public Criteria andJobIdBetween(String value1, String value2) { 228 | addCriterion("job_id between", value1, value2, "jobId"); 229 | return (Criteria) this; 230 | } 231 | 232 | public Criteria andJobIdNotBetween(String value1, String value2) { 233 | addCriterion("job_id not between", value1, value2, "jobId"); 234 | return (Criteria) this; 235 | } 236 | 237 | public Criteria andJobNameIsNull() { 238 | addCriterion("job_name is null"); 239 | return (Criteria) this; 240 | } 241 | 242 | public Criteria andJobNameIsNotNull() { 243 | addCriterion("job_name is not null"); 244 | return (Criteria) this; 245 | } 246 | 247 | public Criteria andJobNameEqualTo(String value) { 248 | addCriterion("job_name =", value, "jobName"); 249 | return (Criteria) this; 250 | } 251 | 252 | public Criteria andJobNameNotEqualTo(String value) { 253 | addCriterion("job_name <>", value, "jobName"); 254 | return (Criteria) this; 255 | } 256 | 257 | public Criteria andJobNameGreaterThan(String value) { 258 | addCriterion("job_name >", value, "jobName"); 259 | return (Criteria) this; 260 | } 261 | 262 | public Criteria andJobNameGreaterThanOrEqualTo(String value) { 263 | addCriterion("job_name >=", value, "jobName"); 264 | return (Criteria) this; 265 | } 266 | 267 | public Criteria andJobNameLessThan(String value) { 268 | addCriterion("job_name <", value, "jobName"); 269 | return (Criteria) this; 270 | } 271 | 272 | public Criteria andJobNameLessThanOrEqualTo(String value) { 273 | addCriterion("job_name <=", value, "jobName"); 274 | return (Criteria) this; 275 | } 276 | 277 | public Criteria andJobNameLike(String value) { 278 | addCriterion("job_name like", value, "jobName"); 279 | return (Criteria) this; 280 | } 281 | 282 | public Criteria andJobNameNotLike(String value) { 283 | addCriterion("job_name not like", value, "jobName"); 284 | return (Criteria) this; 285 | } 286 | 287 | public Criteria andJobNameIn(List values) { 288 | addCriterion("job_name in", values, "jobName"); 289 | return (Criteria) this; 290 | } 291 | 292 | public Criteria andJobNameNotIn(List values) { 293 | addCriterion("job_name not in", values, "jobName"); 294 | return (Criteria) this; 295 | } 296 | 297 | public Criteria andJobNameBetween(String value1, String value2) { 298 | addCriterion("job_name between", value1, value2, "jobName"); 299 | return (Criteria) this; 300 | } 301 | 302 | public Criteria andJobNameNotBetween(String value1, String value2) { 303 | addCriterion("job_name not between", value1, value2, "jobName"); 304 | return (Criteria) this; 305 | } 306 | 307 | public Criteria andJobStatusIsNull() { 308 | addCriterion("job_status is null"); 309 | return (Criteria) this; 310 | } 311 | 312 | public Criteria andJobStatusIsNotNull() { 313 | addCriterion("job_status is not null"); 314 | return (Criteria) this; 315 | } 316 | 317 | public Criteria andJobStatusEqualTo(String value) { 318 | addCriterion("job_status =", value, "jobStatus"); 319 | return (Criteria) this; 320 | } 321 | 322 | public Criteria andJobStatusNotEqualTo(String value) { 323 | addCriterion("job_status <>", value, "jobStatus"); 324 | return (Criteria) this; 325 | } 326 | 327 | public Criteria andJobStatusGreaterThan(String value) { 328 | addCriterion("job_status >", value, "jobStatus"); 329 | return (Criteria) this; 330 | } 331 | 332 | public Criteria andJobStatusGreaterThanOrEqualTo(String value) { 333 | addCriterion("job_status >=", value, "jobStatus"); 334 | return (Criteria) this; 335 | } 336 | 337 | public Criteria andJobStatusLessThan(String value) { 338 | addCriterion("job_status <", value, "jobStatus"); 339 | return (Criteria) this; 340 | } 341 | 342 | public Criteria andJobStatusLessThanOrEqualTo(String value) { 343 | addCriterion("job_status <=", value, "jobStatus"); 344 | return (Criteria) this; 345 | } 346 | 347 | public Criteria andJobStatusLike(String value) { 348 | addCriterion("job_status like", value, "jobStatus"); 349 | return (Criteria) this; 350 | } 351 | 352 | public Criteria andJobStatusNotLike(String value) { 353 | addCriterion("job_status not like", value, "jobStatus"); 354 | return (Criteria) this; 355 | } 356 | 357 | public Criteria andJobStatusIn(List values) { 358 | addCriterion("job_status in", values, "jobStatus"); 359 | return (Criteria) this; 360 | } 361 | 362 | public Criteria andJobStatusNotIn(List values) { 363 | addCriterion("job_status not in", values, "jobStatus"); 364 | return (Criteria) this; 365 | } 366 | 367 | public Criteria andJobStatusBetween(String value1, String value2) { 368 | addCriterion("job_status between", value1, value2, "jobStatus"); 369 | return (Criteria) this; 370 | } 371 | 372 | public Criteria andJobStatusNotBetween(String value1, String value2) { 373 | addCriterion("job_status not between", value1, value2, "jobStatus"); 374 | return (Criteria) this; 375 | } 376 | 377 | public Criteria andJobGroupIsNull() { 378 | addCriterion("job_Group is null"); 379 | return (Criteria) this; 380 | } 381 | 382 | public Criteria andJobGroupIsNotNull() { 383 | addCriterion("job_Group is not null"); 384 | return (Criteria) this; 385 | } 386 | 387 | public Criteria andJobGroupEqualTo(String value) { 388 | addCriterion("job_Group =", value, "jobGroup"); 389 | return (Criteria) this; 390 | } 391 | 392 | public Criteria andJobGroupNotEqualTo(String value) { 393 | addCriterion("job_Group <>", value, "jobGroup"); 394 | return (Criteria) this; 395 | } 396 | 397 | public Criteria andJobGroupGreaterThan(String value) { 398 | addCriterion("job_Group >", value, "jobGroup"); 399 | return (Criteria) this; 400 | } 401 | 402 | public Criteria andJobGroupGreaterThanOrEqualTo(String value) { 403 | addCriterion("job_Group >=", value, "jobGroup"); 404 | return (Criteria) this; 405 | } 406 | 407 | public Criteria andJobGroupLessThan(String value) { 408 | addCriterion("job_Group <", value, "jobGroup"); 409 | return (Criteria) this; 410 | } 411 | 412 | public Criteria andJobGroupLessThanOrEqualTo(String value) { 413 | addCriterion("job_Group <=", value, "jobGroup"); 414 | return (Criteria) this; 415 | } 416 | 417 | public Criteria andJobGroupLike(String value) { 418 | addCriterion("job_Group like", value, "jobGroup"); 419 | return (Criteria) this; 420 | } 421 | 422 | public Criteria andJobGroupNotLike(String value) { 423 | addCriterion("job_Group not like", value, "jobGroup"); 424 | return (Criteria) this; 425 | } 426 | 427 | public Criteria andJobGroupIn(List values) { 428 | addCriterion("job_Group in", values, "jobGroup"); 429 | return (Criteria) this; 430 | } 431 | 432 | public Criteria andJobGroupNotIn(List values) { 433 | addCriterion("job_Group not in", values, "jobGroup"); 434 | return (Criteria) this; 435 | } 436 | 437 | public Criteria andJobGroupBetween(String value1, String value2) { 438 | addCriterion("job_Group between", value1, value2, "jobGroup"); 439 | return (Criteria) this; 440 | } 441 | 442 | public Criteria andJobGroupNotBetween(String value1, String value2) { 443 | addCriterion("job_Group not between", value1, value2, "jobGroup"); 444 | return (Criteria) this; 445 | } 446 | 447 | public Criteria andCronExpressionIsNull() { 448 | addCriterion("cron_Expression is null"); 449 | return (Criteria) this; 450 | } 451 | 452 | public Criteria andCronExpressionIsNotNull() { 453 | addCriterion("cron_Expression is not null"); 454 | return (Criteria) this; 455 | } 456 | 457 | public Criteria andCronExpressionEqualTo(String value) { 458 | addCriterion("cron_Expression =", value, "cronExpression"); 459 | return (Criteria) this; 460 | } 461 | 462 | public Criteria andCronExpressionNotEqualTo(String value) { 463 | addCriterion("cron_Expression <>", value, "cronExpression"); 464 | return (Criteria) this; 465 | } 466 | 467 | public Criteria andCronExpressionGreaterThan(String value) { 468 | addCriterion("cron_Expression >", value, "cronExpression"); 469 | return (Criteria) this; 470 | } 471 | 472 | public Criteria andCronExpressionGreaterThanOrEqualTo(String value) { 473 | addCriterion("cron_Expression >=", value, "cronExpression"); 474 | return (Criteria) this; 475 | } 476 | 477 | public Criteria andCronExpressionLessThan(String value) { 478 | addCriterion("cron_Expression <", value, "cronExpression"); 479 | return (Criteria) this; 480 | } 481 | 482 | public Criteria andCronExpressionLessThanOrEqualTo(String value) { 483 | addCriterion("cron_Expression <=", value, "cronExpression"); 484 | return (Criteria) this; 485 | } 486 | 487 | public Criteria andCronExpressionLike(String value) { 488 | addCriterion("cron_Expression like", value, "cronExpression"); 489 | return (Criteria) this; 490 | } 491 | 492 | public Criteria andCronExpressionNotLike(String value) { 493 | addCriterion("cron_Expression not like", value, "cronExpression"); 494 | return (Criteria) this; 495 | } 496 | 497 | public Criteria andCronExpressionIn(List values) { 498 | addCriterion("cron_Expression in", values, "cronExpression"); 499 | return (Criteria) this; 500 | } 501 | 502 | public Criteria andCronExpressionNotIn(List values) { 503 | addCriterion("cron_Expression not in", values, "cronExpression"); 504 | return (Criteria) this; 505 | } 506 | 507 | public Criteria andCronExpressionBetween(String value1, String value2) { 508 | addCriterion("cron_Expression between", value1, value2, "cronExpression"); 509 | return (Criteria) this; 510 | } 511 | 512 | public Criteria andCronExpressionNotBetween(String value1, String value2) { 513 | addCriterion("cron_Expression not between", value1, value2, "cronExpression"); 514 | return (Criteria) this; 515 | } 516 | 517 | public Criteria andDescriptionIsNull() { 518 | addCriterion("description is null"); 519 | return (Criteria) this; 520 | } 521 | 522 | public Criteria andDescriptionIsNotNull() { 523 | addCriterion("description is not null"); 524 | return (Criteria) this; 525 | } 526 | 527 | public Criteria andDescriptionEqualTo(String value) { 528 | addCriterion("description =", value, "description"); 529 | return (Criteria) this; 530 | } 531 | 532 | public Criteria andDescriptionNotEqualTo(String value) { 533 | addCriterion("description <>", value, "description"); 534 | return (Criteria) this; 535 | } 536 | 537 | public Criteria andDescriptionGreaterThan(String value) { 538 | addCriterion("description >", value, "description"); 539 | return (Criteria) this; 540 | } 541 | 542 | public Criteria andDescriptionGreaterThanOrEqualTo(String value) { 543 | addCriterion("description >=", value, "description"); 544 | return (Criteria) this; 545 | } 546 | 547 | public Criteria andDescriptionLessThan(String value) { 548 | addCriterion("description <", value, "description"); 549 | return (Criteria) this; 550 | } 551 | 552 | public Criteria andDescriptionLessThanOrEqualTo(String value) { 553 | addCriterion("description <=", value, "description"); 554 | return (Criteria) this; 555 | } 556 | 557 | public Criteria andDescriptionLike(String value) { 558 | addCriterion("description like", value, "description"); 559 | return (Criteria) this; 560 | } 561 | 562 | public Criteria andDescriptionNotLike(String value) { 563 | addCriterion("description not like", value, "description"); 564 | return (Criteria) this; 565 | } 566 | 567 | public Criteria andDescriptionIn(List values) { 568 | addCriterion("description in", values, "description"); 569 | return (Criteria) this; 570 | } 571 | 572 | public Criteria andDescriptionNotIn(List values) { 573 | addCriterion("description not in", values, "description"); 574 | return (Criteria) this; 575 | } 576 | 577 | public Criteria andDescriptionBetween(String value1, String value2) { 578 | addCriterion("description between", value1, value2, "description"); 579 | return (Criteria) this; 580 | } 581 | 582 | public Criteria andDescriptionNotBetween(String value1, String value2) { 583 | addCriterion("description not between", value1, value2, "description"); 584 | return (Criteria) this; 585 | } 586 | 587 | public Criteria andBeanNameIsNull() { 588 | addCriterion("bean_name is null"); 589 | return (Criteria) this; 590 | } 591 | 592 | public Criteria andBeanNameIsNotNull() { 593 | addCriterion("bean_name is not null"); 594 | return (Criteria) this; 595 | } 596 | 597 | public Criteria andBeanNameEqualTo(String value) { 598 | addCriterion("bean_name =", value, "beanName"); 599 | return (Criteria) this; 600 | } 601 | 602 | public Criteria andBeanNameNotEqualTo(String value) { 603 | addCriterion("bean_name <>", value, "beanName"); 604 | return (Criteria) this; 605 | } 606 | 607 | public Criteria andBeanNameGreaterThan(String value) { 608 | addCriterion("bean_name >", value, "beanName"); 609 | return (Criteria) this; 610 | } 611 | 612 | public Criteria andBeanNameGreaterThanOrEqualTo(String value) { 613 | addCriterion("bean_name >=", value, "beanName"); 614 | return (Criteria) this; 615 | } 616 | 617 | public Criteria andBeanNameLessThan(String value) { 618 | addCriterion("bean_name <", value, "beanName"); 619 | return (Criteria) this; 620 | } 621 | 622 | public Criteria andBeanNameLessThanOrEqualTo(String value) { 623 | addCriterion("bean_name <=", value, "beanName"); 624 | return (Criteria) this; 625 | } 626 | 627 | public Criteria andBeanNameLike(String value) { 628 | addCriterion("bean_name like", value, "beanName"); 629 | return (Criteria) this; 630 | } 631 | 632 | public Criteria andBeanNameNotLike(String value) { 633 | addCriterion("bean_name not like", value, "beanName"); 634 | return (Criteria) this; 635 | } 636 | 637 | public Criteria andBeanNameIn(List values) { 638 | addCriterion("bean_name in", values, "beanName"); 639 | return (Criteria) this; 640 | } 641 | 642 | public Criteria andBeanNameNotIn(List values) { 643 | addCriterion("bean_name not in", values, "beanName"); 644 | return (Criteria) this; 645 | } 646 | 647 | public Criteria andBeanNameBetween(String value1, String value2) { 648 | addCriterion("bean_name between", value1, value2, "beanName"); 649 | return (Criteria) this; 650 | } 651 | 652 | public Criteria andBeanNameNotBetween(String value1, String value2) { 653 | addCriterion("bean_name not between", value1, value2, "beanName"); 654 | return (Criteria) this; 655 | } 656 | 657 | public Criteria andMethodNameIsNull() { 658 | addCriterion("method_name is null"); 659 | return (Criteria) this; 660 | } 661 | 662 | public Criteria andMethodNameIsNotNull() { 663 | addCriterion("method_name is not null"); 664 | return (Criteria) this; 665 | } 666 | 667 | public Criteria andMethodNameEqualTo(String value) { 668 | addCriterion("method_name =", value, "methodName"); 669 | return (Criteria) this; 670 | } 671 | 672 | public Criteria andMethodNameNotEqualTo(String value) { 673 | addCriterion("method_name <>", value, "methodName"); 674 | return (Criteria) this; 675 | } 676 | 677 | public Criteria andMethodNameGreaterThan(String value) { 678 | addCriterion("method_name >", value, "methodName"); 679 | return (Criteria) this; 680 | } 681 | 682 | public Criteria andMethodNameGreaterThanOrEqualTo(String value) { 683 | addCriterion("method_name >=", value, "methodName"); 684 | return (Criteria) this; 685 | } 686 | 687 | public Criteria andMethodNameLessThan(String value) { 688 | addCriterion("method_name <", value, "methodName"); 689 | return (Criteria) this; 690 | } 691 | 692 | public Criteria andMethodNameLessThanOrEqualTo(String value) { 693 | addCriterion("method_name <=", value, "methodName"); 694 | return (Criteria) this; 695 | } 696 | 697 | public Criteria andMethodNameLike(String value) { 698 | addCriterion("method_name like", value, "methodName"); 699 | return (Criteria) this; 700 | } 701 | 702 | public Criteria andMethodNameNotLike(String value) { 703 | addCriterion("method_name not like", value, "methodName"); 704 | return (Criteria) this; 705 | } 706 | 707 | public Criteria andMethodNameIn(List values) { 708 | addCriterion("method_name in", values, "methodName"); 709 | return (Criteria) this; 710 | } 711 | 712 | public Criteria andMethodNameNotIn(List values) { 713 | addCriterion("method_name not in", values, "methodName"); 714 | return (Criteria) this; 715 | } 716 | 717 | public Criteria andMethodNameBetween(String value1, String value2) { 718 | addCriterion("method_name between", value1, value2, "methodName"); 719 | return (Criteria) this; 720 | } 721 | 722 | public Criteria andMethodNameNotBetween(String value1, String value2) { 723 | addCriterion("method_name not between", value1, value2, "methodName"); 724 | return (Criteria) this; 725 | } 726 | } 727 | 728 | public static class Criteria extends GeneratedCriteria { 729 | 730 | protected Criteria() { 731 | super(); 732 | } 733 | } 734 | 735 | public static class Criterion { 736 | private String condition; 737 | 738 | private Object value; 739 | 740 | private Object secondValue; 741 | 742 | private boolean noValue; 743 | 744 | private boolean singleValue; 745 | 746 | private boolean betweenValue; 747 | 748 | private boolean listValue; 749 | 750 | private String typeHandler; 751 | 752 | public String getCondition() { 753 | return condition; 754 | } 755 | 756 | public Object getValue() { 757 | return value; 758 | } 759 | 760 | public Object getSecondValue() { 761 | return secondValue; 762 | } 763 | 764 | public boolean isNoValue() { 765 | return noValue; 766 | } 767 | 768 | public boolean isSingleValue() { 769 | return singleValue; 770 | } 771 | 772 | public boolean isBetweenValue() { 773 | return betweenValue; 774 | } 775 | 776 | public boolean isListValue() { 777 | return listValue; 778 | } 779 | 780 | public String getTypeHandler() { 781 | return typeHandler; 782 | } 783 | 784 | protected Criterion(String condition) { 785 | super(); 786 | this.condition = condition; 787 | this.typeHandler = null; 788 | this.noValue = true; 789 | } 790 | 791 | protected Criterion(String condition, Object value, String typeHandler) { 792 | super(); 793 | this.condition = condition; 794 | this.value = value; 795 | this.typeHandler = typeHandler; 796 | if (value instanceof List) { 797 | this.listValue = true; 798 | } else { 799 | this.singleValue = true; 800 | } 801 | } 802 | 803 | protected Criterion(String condition, Object value) { 804 | this(condition, value, null); 805 | } 806 | 807 | protected Criterion(String condition, Object value, Object secondValue, String typeHandler) { 808 | super(); 809 | this.condition = condition; 810 | this.value = value; 811 | this.secondValue = secondValue; 812 | this.typeHandler = typeHandler; 813 | this.betweenValue = true; 814 | } 815 | 816 | protected Criterion(String condition, Object value, Object secondValue) { 817 | this(condition, value, secondValue, null); 818 | } 819 | } 820 | } -------------------------------------------------------------------------------- /src/main/resources/static/js/bootstrap-select.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap-select v1.12.1 (http://silviomoreto.github.io/bootstrap-select) 3 | * 4 | * Copyright 2013-2016 bootstrap-select 5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE) 6 | */ 7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof module&&module.exports?module.exports=b(require("jquery")):b(a.jQuery)}(this,function(a){!function(a){"use strict";function b(b){var c=[{re:/[\xC0-\xC6]/g,ch:"A"},{re:/[\xE0-\xE6]/g,ch:"a"},{re:/[\xC8-\xCB]/g,ch:"E"},{re:/[\xE8-\xEB]/g,ch:"e"},{re:/[\xCC-\xCF]/g,ch:"I"},{re:/[\xEC-\xEF]/g,ch:"i"},{re:/[\xD2-\xD6]/g,ch:"O"},{re:/[\xF2-\xF6]/g,ch:"o"},{re:/[\xD9-\xDC]/g,ch:"U"},{re:/[\xF9-\xFC]/g,ch:"u"},{re:/[\xC7-\xE7]/g,ch:"c"},{re:/[\xD1]/g,ch:"N"},{re:/[\xF1]/g,ch:"n"}];return a.each(c,function(){b=b?b.replace(this.re,this.ch):""}),b}function c(b){var c=arguments,d=b;[].shift.apply(c);var e,f=this.each(function(){var b=a(this);if(b.is("select")){var f=b.data("selectpicker"),g="object"==typeof d&&d;if(f){if(g)for(var h in g)g.hasOwnProperty(h)&&(f.options[h]=g[h])}else{var i=a.extend({},k.DEFAULTS,a.fn.selectpicker.defaults||{},b.data(),g);i.template=a.extend({},k.DEFAULTS.template,a.fn.selectpicker.defaults?a.fn.selectpicker.defaults.template:{},b.data().template,g.template),b.data("selectpicker",f=new k(this,i))}"string"==typeof d&&(e=f[d]instanceof Function?f[d].apply(f,c):f.options[d])}});return"undefined"!=typeof e?e:f}String.prototype.includes||!function(){var a={}.toString,b=function(){try{var a={},b=Object.defineProperty,c=b(a,a,a)&&b}catch(a){}return c}(),c="".indexOf,d=function(b){if(null==this)throw new TypeError;var d=String(this);if(b&&"[object RegExp]"==a.call(b))throw new TypeError;var e=d.length,f=String(b),g=f.length,h=arguments.length>1?arguments[1]:void 0,i=h?Number(h):0;i!=i&&(i=0);var j=Math.min(Math.max(i,0),e);return!(g+j>e)&&c.call(d,f,i)!=-1};b?b(String.prototype,"includes",{value:d,configurable:!0,writable:!0}):String.prototype.includes=d}(),String.prototype.startsWith||!function(){var a=function(){try{var a={},b=Object.defineProperty,c=b(a,a,a)&&b}catch(a){}return c}(),b={}.toString,c=function(a){if(null==this)throw new TypeError;var c=String(this);if(a&&"[object RegExp]"==b.call(a))throw new TypeError;var d=c.length,e=String(a),f=e.length,g=arguments.length>1?arguments[1]:void 0,h=g?Number(g):0;h!=h&&(h=0);var i=Math.min(Math.max(h,0),d);if(f+i>d)return!1;for(var j=-1;++j":">",'"':""","'":"'","`":"`"},g={"&":"&","<":"<",">":">",""":'"',"'":"'","`":"`"},h=function(a){var b=function(b){return a[b]},c="(?:"+Object.keys(a).join("|")+")",d=RegExp(c),e=RegExp(c,"g");return function(a){return a=null==a?"":""+a,d.test(a)?a.replace(e,b):a}},i=h(f),j=h(g),k=function(b,c){d.useDefault||(a.valHooks.select.set=d._set,d.useDefault=!0),this.$element=a(b),this.$newElement=null,this.$button=null,this.$menu=null,this.$lis=null,this.options=c,null===this.options.title&&(this.options.title=this.$element.attr("title"));var e=this.options.windowPadding;"number"==typeof e&&(this.options.windowPadding=[e,e,e,e]),this.val=k.prototype.val,this.render=k.prototype.render,this.refresh=k.prototype.refresh,this.setStyle=k.prototype.setStyle,this.selectAll=k.prototype.selectAll,this.deselectAll=k.prototype.deselectAll,this.destroy=k.prototype.destroy,this.remove=k.prototype.remove,this.show=k.prototype.show,this.hide=k.prototype.hide,this.init()};k.VERSION="1.12.1",k.DEFAULTS={noneSelectedText:"请选择",noneResultsText:"No results matched {0}",countSelectedText:function(a,b){return 1==a?"{0} item selected":"{0} items selected"},maxOptionsText:function(a,b){return[1==a?"Limit reached ({n} item max)":"Limit reached ({n} items max)",1==b?"Group limit reached ({n} item max)":"Group limit reached ({n} items max)"]},selectAllText:"Select All",deselectAllText:"Deselect All",doneButton:!1,doneButtonText:"Close",multipleSeparator:", ",styleBase:"btn",style:"btn-default",size:"auto",title:null,selectedTextFormat:"values",width:!1,container:!1,hideDisabled:!1,showSubtext:!1,showIcon:!0,showContent:!0,dropupAuto:!0,header:!1,liveSearch:!1,liveSearchPlaceholder:null,liveSearchNormalize:!1,liveSearchStyle:"contains",actionsBox:!1,iconBase:"glyphicon",tickIcon:"glyphicon-ok",showTick:!1,template:{caret:''},maxOptions:!1,mobile:!1,selectOnTab:!1,dropdownAlignRight:!1,windowPadding:0},k.prototype={constructor:k,init:function(){var b=this,c=this.$element.attr("id");this.$element.addClass("bs-select-hidden"),this.liObj={},this.multiple=this.$element.prop("multiple"),this.autofocus=this.$element.prop("autofocus"),this.$newElement=this.createView(),this.$element.after(this.$newElement).appendTo(this.$newElement),this.$button=this.$newElement.children("button"),this.$menu=this.$newElement.children(".dropdown-menu"),this.$menuInner=this.$menu.children(".inner"),this.$searchbox=this.$menu.find("input"),this.$element.removeClass("bs-select-hidden"),this.options.dropdownAlignRight===!0&&this.$menu.addClass("dropdown-menu-right"),"undefined"!=typeof c&&(this.$button.attr("data-id",c),a('label[for="'+c+'"]').click(function(a){a.preventDefault(),b.$button.focus()})),this.checkDisabled(),this.clickListener(),this.options.liveSearch&&this.liveSearchListener(),this.render(),this.setStyle(),this.setWidth(),this.options.container&&this.selectPosition(),this.$menu.data("this",this),this.$newElement.data("this",this),this.options.mobile&&this.mobile(),this.$newElement.on({"hide.bs.dropdown":function(a){b.$menuInner.attr("aria-expanded",!1),b.$element.trigger("hide.bs.select",a)},"hidden.bs.dropdown":function(a){b.$element.trigger("hidden.bs.select",a)},"show.bs.dropdown":function(a){b.$menuInner.attr("aria-expanded",!0),b.$element.trigger("show.bs.select",a)},"shown.bs.dropdown":function(a){b.$element.trigger("shown.bs.select",a)}}),b.$element[0].hasAttribute("required")&&this.$element.on("invalid",function(){b.$button.addClass("bs-invalid").focus(),b.$element.on({"focus.bs.select":function(){b.$button.focus(),b.$element.off("focus.bs.select")},"shown.bs.select":function(){b.$element.val(b.$element.val()).off("shown.bs.select")},"rendered.bs.select":function(){this.validity.valid&&b.$button.removeClass("bs-invalid"),b.$element.off("rendered.bs.select")}})}),setTimeout(function(){b.$element.trigger("loaded.bs.select")})},createDropdown:function(){var b=this.multiple||this.options.showTick?" show-tick":"",c=this.$element.parent().hasClass("input-group")?" input-group-btn":"",d=this.autofocus?" autofocus":"",e=this.options.header?'
'+this.options.header+"
":"",f=this.options.liveSearch?'':"",g=this.multiple&&this.options.actionsBox?'
":"",h=this.multiple&&this.options.doneButton?'
":"",j='
";return a(j)},createView:function(){var a=this.createDropdown(),b=this.createLi();return a.find("ul")[0].innerHTML=b,a},reloadLi:function(){var a=this.createLi();this.$menuInner[0].innerHTML=a},createLi:function(){var c=this,d=[],e=0,f=document.createElement("option"),g=-1,h=function(a,b,c,d){return""+a+""},j=function(d,e,f,g){return''+d+''};if(this.options.title&&!this.multiple&&(g--,!this.$element.find(".bs-title-option").length)){var k=this.$element[0];f.className="bs-title-option",f.innerHTML=this.options.title,f.value="",k.insertBefore(f,k.firstChild);var l=a(k.options[k.selectedIndex]);void 0===l.attr("selected")&&void 0===this.$element.data("selected")&&(f.selected=!0)}return this.$element.find("option").each(function(b){var f=a(this);if(g++,!f.hasClass("bs-title-option")){var k=this.className||"",l=this.style.cssText,m=f.data("content")?f.data("content"):f.html(),n=f.data("tokens")?f.data("tokens"):null,o="undefined"!=typeof f.data("subtext")?''+f.data("subtext")+"":"",p="undefined"!=typeof f.data("icon")?' ':"",q=f.parent(),r="OPTGROUP"===q[0].tagName,s=r&&q[0].disabled,t=this.disabled||s;if(""!==p&&t&&(p=""+p+""),c.options.hideDisabled&&(t&&!r||s))return void g--;if(f.data("content")||(m=p+''+m+o+""),r&&f.data("divider")!==!0){if(c.options.hideDisabled&&t){if(void 0===q.data("allOptionsDisabled")){var u=q.children();q.data("allOptionsDisabled",u.filter(":disabled").length===u.length)}if(q.data("allOptionsDisabled"))return void g--}var v=" "+q[0].className||"";if(0===f.index()){e+=1;var w=q[0].label,x="undefined"!=typeof q.data("subtext")?''+q.data("subtext")+"":"",y=q.data("icon")?' ':"";w=y+''+i(w)+x+"",0!==b&&d.length>0&&(g++,d.push(h("",null,"divider",e+"div"))),g++,d.push(h(w,null,"dropdown-header"+v,e))}if(c.options.hideDisabled&&t)return void g--;d.push(h(j(m,"opt "+k+v,l,n),b,"",e))}else if(f.data("divider")===!0)d.push(h("",b,"divider"));else if(f.data("hidden")===!0)d.push(h(j(m,k,l,n),b,"hidden is-hidden"));else{var z=this.previousElementSibling&&"OPTGROUP"===this.previousElementSibling.tagName;if(!z&&c.options.hideDisabled)for(var A=a(this).prevAll(),B=0;B ':"";return b=d.options.showSubtext&&c.data("subtext")&&!d.multiple?' '+c.data("subtext")+"":"","undefined"!=typeof c.attr("title")?c.attr("title"):c.data("content")&&d.options.showContent?c.data("content").toString():e+c.html()+b}}).toArray(),f=this.multiple?e.join(this.options.multipleSeparator):e[0];if(this.multiple&&this.options.selectedTextFormat.indexOf("count")>-1){var g=this.options.selectedTextFormat.split(">");if(g.length>1&&e.length>g[1]||1==g.length&&e.length>=2){c=this.options.hideDisabled?", [disabled]":"";var h=this.$element.find("option").not('[data-divider="true"], [data-hidden="true"]'+c).length,i="function"==typeof this.options.countSelectedText?this.options.countSelectedText(e.length,h):this.options.countSelectedText;f=i.replace("{0}",e.length.toString()).replace("{1}",h.toString())}}void 0==this.options.title&&(this.options.title=this.$element.attr("title")),"static"==this.options.selectedTextFormat&&(f=this.options.title),f||(f="undefined"!=typeof this.options.title?this.options.title:this.options.noneSelectedText),this.$button.attr("title",j(a.trim(f.replace(/<[^>]*>?/g,"")))),this.$button.children(".filter-option").html(f),this.$element.trigger("rendered.bs.select")},setStyle:function(a,b){this.$element.attr("class")&&this.$newElement.addClass(this.$element.attr("class").replace(/selectpicker|mobile-device|bs-select-hidden|validate\[.*\]/gi,""));var c=a?a:this.options.style;"add"==b?this.$button.addClass(c):"remove"==b?this.$button.removeClass(c):(this.$button.removeClass(this.options.style),this.$button.addClass(c))},liHeight:function(b){if(b||this.options.size!==!1&&!this.sizeInfo){var c=document.createElement("div"),d=document.createElement("div"),e=document.createElement("ul"),f=document.createElement("li"),g=document.createElement("li"),h=document.createElement("a"),i=document.createElement("span"),j=this.options.header&&this.$menu.find(".popover-title").length>0?this.$menu.find(".popover-title")[0].cloneNode(!0):null,k=this.options.liveSearch?document.createElement("div"):null,l=this.options.actionsBox&&this.multiple&&this.$menu.find(".bs-actionsbox").length>0?this.$menu.find(".bs-actionsbox")[0].cloneNode(!0):null,m=this.options.doneButton&&this.multiple&&this.$menu.find(".bs-donebutton").length>0?this.$menu.find(".bs-donebutton")[0].cloneNode(!0):null;if(i.className="text",c.className=this.$menu[0].parentNode.className+" open",d.className="dropdown-menu open",e.className="dropdown-menu inner",f.className="divider",i.appendChild(document.createTextNode("Inner text")),h.appendChild(i),g.appendChild(h),e.appendChild(g),e.appendChild(f),j&&d.appendChild(j),k){var n=document.createElement("span");k.className="bs-searchbox",n.className="form-control",k.appendChild(n),d.appendChild(k)}l&&d.appendChild(l),d.appendChild(e),m&&d.appendChild(m),c.appendChild(d),document.body.appendChild(c);var o=h.offsetHeight,p=j?j.offsetHeight:0,q=k?k.offsetHeight:0,r=l?l.offsetHeight:0,s=m?m.offsetHeight:0,t=a(f).outerHeight(!0),u="function"==typeof getComputedStyle&&getComputedStyle(d),v=u?null:a(d),w={vert:parseInt(u?u.paddingTop:v.css("paddingTop"))+parseInt(u?u.paddingBottom:v.css("paddingBottom"))+parseInt(u?u.borderTopWidth:v.css("borderTopWidth"))+parseInt(u?u.borderBottomWidth:v.css("borderBottomWidth")),horiz:parseInt(u?u.paddingLeft:v.css("paddingLeft"))+parseInt(u?u.paddingRight:v.css("paddingRight"))+parseInt(u?u.borderLeftWidth:v.css("borderLeftWidth"))+parseInt(u?u.borderRightWidth:v.css("borderRightWidth"))},x={vert:w.vert+parseInt(u?u.marginTop:v.css("marginTop"))+parseInt(u?u.marginBottom:v.css("marginBottom"))+2,horiz:w.horiz+parseInt(u?u.marginLeft:v.css("marginLeft"))+parseInt(u?u.marginRight:v.css("marginRight"))+2};document.body.removeChild(c),this.sizeInfo={liHeight:o,headerHeight:p,searchHeight:q,actionsHeight:r,doneButtonHeight:s,dividerHeight:t,menuPadding:w,menuExtras:x}}},setSize:function(){if(this.findLis(),this.liHeight(),this.options.header&&this.$menu.css("padding-top",0),this.options.size!==!1){var b,c,d,e,f,g,h,i,j=this,k=this.$menu,l=this.$menuInner,m=a(window),n=this.$newElement[0].offsetHeight,o=this.$newElement[0].offsetWidth,p=this.sizeInfo.liHeight,q=this.sizeInfo.headerHeight,r=this.sizeInfo.searchHeight,s=this.sizeInfo.actionsHeight,t=this.sizeInfo.doneButtonHeight,u=this.sizeInfo.dividerHeight,v=this.sizeInfo.menuPadding,w=this.sizeInfo.menuExtras,x=this.options.hideDisabled?".disabled":"",y=function(){var b,c=j.$newElement.offset(),d=a(j.options.container);j.options.container&&!d.is("body")?(b=d.offset(),b.top+=parseInt(d.css("borderTopWidth")),b.left+=parseInt(d.css("borderLeftWidth"))):b={top:0,left:0};var e=j.options.windowPadding;f=c.top-b.top-m.scrollTop(),g=m.height()-f-n-b.top-e[2],h=c.left-b.left-m.scrollLeft(),i=m.width()-h-o-b.left-e[1],f-=e[0],h-=e[3]};if(y(),"auto"===this.options.size){var z=function(){var m,n=function(b,c){return function(d){return c?d.classList?d.classList.contains(b):a(d).hasClass(b):!(d.classList?d.classList.contains(b):a(d).hasClass(b))}},u=j.$menuInner[0].getElementsByTagName("li"),x=Array.prototype.filter?Array.prototype.filter.call(u,n("hidden",!1)):j.$lis.not(".hidden"),z=Array.prototype.filter?Array.prototype.filter.call(x,n("dropdown-header",!0)):x.filter(".dropdown-header");y(),b=g-w.vert,c=i-w.horiz,j.options.container?(k.data("height")||k.data("height",k.height()),d=k.data("height"),k.data("width")||k.data("width",k.width()),e=k.data("width")):(d=k.height(),e=k.width()),j.options.dropupAuto&&j.$newElement.toggleClass("dropup",f>g&&b-w.verti&&c-w.horiz3?3*p+w.vert-2:0,k.css({"max-height":b+"px",overflow:"hidden","min-height":m+q+r+s+t+"px"}),l.css({"max-height":b-q-r-s-t-v.vert+"px","overflow-y":"auto","min-height":Math.max(m-v.vert,0)+"px"})};z(),this.$searchbox.off("input.getSize propertychange.getSize").on("input.getSize propertychange.getSize",z),m.off("resize.getSize scroll.getSize").on("resize.getSize scroll.getSize",z)}else if(this.options.size&&"auto"!=this.options.size&&this.$lis.not(x).length>this.options.size){var A=this.$lis.not(".divider").not(x).children().slice(0,this.options.size).last().parent().index(),B=this.$lis.slice(0,A+1).filter(".divider").length;b=p*this.options.size+B*u+v.vert,j.options.container?(k.data("height")||k.data("height",k.height()),d=k.data("height")):d=k.height(),j.options.dropupAuto&&this.$newElement.toggleClass("dropup",f>g&&b-w.vert');var b,c,d,e=this,f=a(this.options.container),g=function(a){e.$bsContainer.addClass(a.attr("class").replace(/form-control|fit-width/gi,"")).toggleClass("dropup",a.hasClass("dropup")),b=a.offset(),f.is("body")?c={top:0,left:0}:(c=f.offset(),c.top+=parseInt(f.css("borderTopWidth"))-f.scrollTop(),c.left+=parseInt(f.css("borderLeftWidth"))-f.scrollLeft()),d=a.hasClass("dropup")?0:a[0].offsetHeight,e.$bsContainer.css({top:b.top-c.top+d,left:b.left-c.left,width:a[0].offsetWidth})};this.$button.on("click",function(){var b=a(this);e.isDisabled()||(g(e.$newElement),e.$bsContainer.appendTo(e.options.container).toggleClass("open",!b.hasClass("open")).append(e.$menu))}),a(window).on("resize scroll",function(){g(e.$newElement)}),this.$element.on("hide.bs.select",function(){e.$menu.data("height",e.$menu.height()),e.$bsContainer.detach()})},setSelected:function(a,b,c){c||(this.togglePlaceholder(),c=this.findLis().eq(this.liObj[a])),c.toggleClass("selected",b).find("a").attr("aria-selected",b)},setDisabled:function(a,b,c){c||(c=this.findLis().eq(this.liObj[a])),b?c.addClass("disabled").children("a").attr("href","#").attr("tabindex",-1).attr("aria-disabled",!0):c.removeClass("disabled").children("a").removeAttr("href").attr("tabindex",0).attr("aria-disabled",!1)},isDisabled:function(){return this.$element[0].disabled},checkDisabled:function(){var a=this;this.isDisabled()?(this.$newElement.addClass("disabled"),this.$button.addClass("disabled").attr("tabindex",-1).attr("aria-disabled",!0)):(this.$button.hasClass("disabled")&&(this.$newElement.removeClass("disabled"),this.$button.removeClass("disabled").attr("aria-disabled",!1)),this.$button.attr("tabindex")!=-1||this.$element.data("tabindex")||this.$button.removeAttr("tabindex")),this.$button.click(function(){return!a.isDisabled()})},togglePlaceholder:function(){var a=this.$element.val();this.$button.toggleClass("bs-placeholder",null===a||""===a||a.constructor===Array&&0===a.length)},tabIndex:function(){this.$element.data("tabindex")!==this.$element.attr("tabindex")&&this.$element.attr("tabindex")!==-98&&"-98"!==this.$element.attr("tabindex")&&(this.$element.data("tabindex",this.$element.attr("tabindex")),this.$button.attr("tabindex",this.$element.data("tabindex"))),this.$element.attr("tabindex",-98)},clickListener:function(){var b=this,c=a(document);c.data("spaceSelect",!1),this.$button.on("keyup",function(a){/(32)/.test(a.keyCode.toString(10))&&c.data("spaceSelect")&&(a.preventDefault(),c.data("spaceSelect",!1))}),this.$button.on("click",function(){b.setSize()}),this.$element.on("shown.bs.select",function(){if(b.options.liveSearch||b.multiple){if(!b.multiple){var a=b.liObj[b.$element[0].selectedIndex];if("number"!=typeof a||b.options.size===!1)return;var c=b.$lis.eq(a)[0].offsetTop-b.$menuInner[0].offsetTop;c=c-b.$menuInner[0].offsetHeight/2+b.sizeInfo.liHeight/2,b.$menuInner[0].scrollTop=c}}else b.$menuInner.find(".selected a").focus()}),this.$menuInner.on("click","li a",function(c){var d=a(this),f=d.parent().data("originalIndex"),g=b.$element.val(),h=b.$element.prop("selectedIndex"),i=!0;if(b.multiple&&1!==b.options.maxOptions&&c.stopPropagation(),c.preventDefault(),!b.isDisabled()&&!d.parent().hasClass("disabled")){var j=b.$element.find("option"),k=j.eq(f),l=k.prop("selected"),m=k.parent("optgroup"),n=b.options.maxOptions,o=m.data("maxOptions")||!1;if(b.multiple){if(k.prop("selected",!l),b.setSelected(f,!l),d.blur(),n!==!1||o!==!1){var p=n');t[2]&&(u=u.replace("{var}",t[2][n>1?0:1]),v=v.replace("{var}",t[2][o>1?0:1])),k.prop("selected",!1),b.$menu.append(w),n&&p&&(w.append(a("
"+u+"
")),i=!1,b.$element.trigger("maxReached.bs.select")),o&&q&&(w.append(a("
"+v+"
")),i=!1,b.$element.trigger("maxReachedGrp.bs.select")),setTimeout(function(){b.setSelected(f,!1)},10),w.delay(750).fadeOut(300,function(){a(this).remove()})}}}else j.prop("selected",!1),k.prop("selected",!0),b.$menuInner.find(".selected").removeClass("selected").find("a").attr("aria-selected",!1),b.setSelected(f,!0);!b.multiple||b.multiple&&1===b.options.maxOptions?b.$button.focus():b.options.liveSearch&&b.$searchbox.focus(),i&&(g!=b.$element.val()&&b.multiple||h!=b.$element.prop("selectedIndex")&&!b.multiple)&&(e=[f,k.prop("selected"),l],b.$element.triggerNative("change"))}}),this.$menu.on("click","li.disabled a, .popover-title, .popover-title :not(.close)",function(c){c.currentTarget==this&&(c.preventDefault(),c.stopPropagation(),b.options.liveSearch&&!a(c.target).hasClass("close")?b.$searchbox.focus():b.$button.focus())}),this.$menuInner.on("click",".divider, .dropdown-header",function(a){a.preventDefault(),a.stopPropagation(),b.options.liveSearch?b.$searchbox.focus():b.$button.focus()}),this.$menu.on("click",".popover-title .close",function(){b.$button.click()}),this.$searchbox.on("click",function(a){a.stopPropagation()}),this.$menu.on("click",".actions-btn",function(c){b.options.liveSearch?b.$searchbox.focus():b.$button.focus(),c.preventDefault(),c.stopPropagation(),a(this).hasClass("bs-select-all")?b.selectAll():b.deselectAll()}),this.$element.change(function(){b.render(!1),b.$element.trigger("changed.bs.select",e),e=null})},liveSearchListener:function(){var c=this,d=a('
  • ');this.$button.on("click.dropdown.data-api",function(){c.$menuInner.find(".active").removeClass("active"),c.$searchbox.val()&&(c.$searchbox.val(""),c.$lis.not(".is-hidden").removeClass("hidden"),d.parent().length&&d.remove()),c.multiple||c.$menuInner.find(".selected").addClass("active"),setTimeout(function(){c.$searchbox.focus()},10)}),this.$searchbox.on("click.dropdown.data-api focus.dropdown.data-api touchend.dropdown.data-api",function(a){a.stopPropagation()}),this.$searchbox.on("input propertychange",function(){if(c.$lis.not(".is-hidden").removeClass("hidden"),c.$lis.filter(".active").removeClass("active"),d.remove(),c.$searchbox.val()){var e,f=c.$lis.not(".is-hidden, .divider, .dropdown-header");if(e=c.options.liveSearchNormalize?f.not(":a"+c._searchStyle()+'("'+b(c.$searchbox.val())+'")'):f.not(":"+c._searchStyle()+'("'+c.$searchbox.val()+'")'),e.length===f.length)d.html(c.options.noneResultsText.replace("{0}",'"'+i(c.$searchbox.val())+'"')),c.$menuInner.append(d),c.$lis.addClass("hidden");else{e.addClass("hidden");var g,h=c.$lis.not(".hidden");h.each(function(b){var c=a(this);c.hasClass("divider")?void 0===g?c.addClass("hidden"):(g&&g.addClass("hidden"),g=c):c.hasClass("dropdown-header")&&h.eq(b+1).data("optgroup")!==c.data("optgroup")?c.addClass("hidden"):g=null}),g&&g.addClass("hidden"),f.not(".hidden").first().addClass("active")}}})},_searchStyle:function(){var a={begins:"ibegins",startsWith:"ibegins"};return a[this.options.liveSearchStyle]||"icontains"},val:function(a){return"undefined"!=typeof a?(this.$element.val(a),this.render(),this.$element):this.$element.val()},changeAll:function(b){if(this.multiple){"undefined"==typeof b&&(b=!0),this.findLis();var c=this.$element.find("option"),d=this.$lis.not(".divider, .dropdown-header, .disabled, .hidden"),e=d.length,f=[];if(b){if(d.filter(".selected").length===d.length)return}else if(0===d.filter(".selected").length)return;d.toggleClass("selected",b);for(var g=0;g=48&&c.keyCode<=57||c.keyCode>=96&&c.keyCode<=105||c.keyCode>=65&&c.keyCode<=90))return o.options.container?o.$button.trigger("click"):(o.setSize(),o.$menu.parent().addClass("open"),l=!0),void o.$searchbox.focus();if(o.options.liveSearch&&(/(^9$|27)/.test(c.keyCode.toString(10))&&l&&(c.preventDefault(),c.stopPropagation(),o.$menuInner.click(),o.$button.focus()),d=a('[role="listbox"] li'+p,n),m.val()||/(38|40)/.test(c.keyCode.toString(10))||0===d.filter(".active").length&&(d=o.$menuInner.find("li"),d=o.options.liveSearchNormalize?d.filter(":a"+o._searchStyle()+"("+b(q[c.keyCode])+")"):d.filter(":"+o._searchStyle()+"("+q[c.keyCode]+")"))),d.length){if(/(38|40)/.test(c.keyCode.toString(10)))e=d.index(d.find("a").filter(":focus").parent()),g=d.filter(p).first().index(),h=d.filter(p).last().index(),f=d.eq(e).nextAll(p).eq(0).index(),i=d.eq(e).prevAll(p).eq(0).index(),j=d.eq(f).prevAll(p).eq(0).index(),o.options.liveSearch&&(d.each(function(b){a(this).hasClass("disabled")||a(this).data("index",b)}),e=d.index(d.filter(".active")),g=d.first().data("index"),h=d.last().data("index"),f=d.eq(e).nextAll().eq(0).data("index"),i=d.eq(e).prevAll().eq(0).data("index"),j=d.eq(f).prevAll().eq(0).data("index")),k=m.data("prevIndex"),38==c.keyCode?(o.options.liveSearch&&e--,e!=j&&e>i&&(e=i),eh&&(e=h),e==k&&(e=g)),m.data("prevIndex",e),o.options.liveSearch?(c.preventDefault(),m.hasClass("dropdown-toggle")||(d.removeClass("active").eq(e).addClass("active").children("a").focus(),m.focus())):d.eq(e).children("a").focus();else if(!m.is("input")){var r,s,t=[];d.each(function(){a(this).hasClass("disabled")||a.trim(a(this).children("a").text().toLowerCase()).substring(0,1)==q[c.keyCode]&&t.push(a(this).index())}),r=a(document).data("keycount"),r++,a(document).data("keycount",r),s=a.trim(a(":focus").text().toLowerCase()).substring(0,1),s!=q[c.keyCode]?(r=1,a(document).data("keycount",r)):r>=t.length&&(a(document).data("keycount",0),r>t.length&&(r=1)),d.eq(t[r-1]).children("a").focus()}if((/(13|32)/.test(c.keyCode.toString(10))||/(^9$)/.test(c.keyCode.toString(10))&&o.options.selectOnTab)&&l){if(/(32)/.test(c.keyCode.toString(10))||c.preventDefault(),o.options.liveSearch)/(32)/.test(c.keyCode.toString(10))||(o.$menuInner.find(".active a").click(),m.focus());else{ 8 | var u=a(":focus");u.click(),u.focus(),c.preventDefault(),a(document).data("spaceSelect",!0)}a(document).data("keycount",0)}(/(^9$|27)/.test(c.keyCode.toString(10))&&l&&(o.multiple||o.options.liveSearch)||/(27)/.test(c.keyCode.toString(10))&&!l)&&(o.$menu.parent().removeClass("open"),o.options.container&&o.$newElement.removeClass("open"),o.$button.focus())}},mobile:function(){this.$element.addClass("mobile-device")},refresh:function(){this.$lis=null,this.liObj={},this.reloadLi(),this.render(),this.checkDisabled(),this.liHeight(!0),this.setStyle(),this.setWidth(),this.$lis&&this.$searchbox.trigger("propertychange"),this.$element.trigger("refreshed.bs.select")},hide:function(){this.$newElement.hide()},show:function(){this.$newElement.show()},remove:function(){this.$newElement.remove(),this.$element.remove()},destroy:function(){this.$newElement.before(this.$element).remove(),this.$bsContainer?this.$bsContainer.remove():this.$menu.remove(),this.$element.off(".bs.select").removeData("selectpicker").removeClass("bs-select-hidden selectpicker")}};var l=a.fn.selectpicker;a.fn.selectpicker=c,a.fn.selectpicker.Constructor=k,a.fn.selectpicker.noConflict=function(){return a.fn.selectpicker=l,this},a(document).data("keycount",0).on("keydown.bs.select",'.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input',k.prototype.keydown).on("focusin.modal",'.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input',function(a){a.stopPropagation()}),a(window).on("load.bs.select.data-api",function(){a(".selectpicker").each(function(){var b=a(this);c.call(b,b.data())})})}(a)}); 9 | //# sourceMappingURL=bootstrap-select.js.map -------------------------------------------------------------------------------- /src/main/resources/static/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2016 Twitter, Inc. 4 | * Licensed under the MIT license 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
    ',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); --------------------------------------------------------------------------------