 
2020-03-16 12:54
@JFinal 倒也是,依赖太多违背精简思想,但是插件机制不知是否有问题,
现在有个bug,用JfinalConfig配置注册插件quartz调度不行,而且启动时也不报错,日志也是DEBUG等级
	/**
	 * 配置插件
	 */
	public void configPlugin(Plugins me) {
			QuartzPlugin quartz = new QuartzPlugin();
			me.add(quartz);
	}
但是改在main 调用就可以,太诡异。。。
 /**
     * 启动入口,运行此 main 方法可以启动项目
     */
    public static void main(String[] args){
        UndertowServer.start(AppConfig.class);
        QuartzPlugin quartz = new QuartzPlugin();
        quartz.start();
    }
 
2020-03-16 10:17
@JFinal 波总,主要Cron4jPlugin 不支持秒级调度,不然肯定首选官方插件啊。波总秒级调度还是比较常见的场景啊
 
2020-03-15 15:29
任务死活不执行,找了半天没找到原因,求助大佬 @JFinal   @埋头苦干
====================== QuartzPlugin  =====================
package com.wjme.app.job.plugin;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.IPlugin;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
public class QuartzPlugin implements IPlugin {
    private List jobs = new ArrayList();
    private SchedulerFactory sf;
    public static Scheduler scheduler;
    private String jobConfig;
    private String confConfig;
    private Properties jobProp;
    public QuartzPlugin(String jobConfig, String confConfig) {
        this.jobConfig = jobConfig;
        this.confConfig = confConfig;
    }
    public QuartzPlugin(String jobConfig) {
        this.jobConfig = jobConfig;
        this.confConfig = "quartz.properties";
    }
    public QuartzPlugin() {
        this.jobConfig = "quartz.properties";
        this.confConfig = "quartz.properties";
    }
    public static void addJob(JobBean job) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobDesc(), job.getJobGroup());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            // 不存在,创建一个
            if (null == trigger) {
                Class j2 = (Class) Class.forName(job.getJobClass());
                JobDetail jobDetail = JobBuilder.newJob(j2).withIdentity(job.getJobDesc(), job.getJobGroup()).build();
                jobDetail.getJobDataMap().put("scheduleJob", job);
                // 表达式调度构建器
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
                // 按新的cronExpression表达式构建一个新的trigger
                trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobDesc(), job.getJobGroup())
                        .withSchedule(scheduleBuilder).build();
                try {
                    scheduler.scheduleJob(jobDetail, trigger);
                } catch (Exception e) {
                    e.printStackTrace();
                    LogKit.error("", e);
                }
            } else {
                // Trigger已存在,那么更新相应的定时设置
                // 表达式调度构建器
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
                // 按新的cronExpression表达式重新构建trigger
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
                // 按新的trigger重新设置job执行
                scheduler.rescheduleJob(triggerKey, trigger);
            }
        } catch (Exception e) {
            e.printStackTrace();
            LogKit.error("", e);
        }
    }
    @Override
    public boolean start() {
        loadJobsFromProperties();
        startJobs();
        return true;
    }
    private void startJobs() {
        try {
            if (StrKit.notBlank(confConfig)) {
                sf = new StdSchedulerFactory(confConfig);
            } else {
                sf = new StdSchedulerFactory();
            }
            scheduler = sf.getScheduler();
        } catch (SchedulerException e) {
            e.printStackTrace();
            LogKit.error("", e);
        }
        for (JobBean entry : jobs) {
            addJob(entry);
        }
        try {
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
            LogKit.error("", e);
        }
    }
    private void loadJobsFromProperties() {
        if (StrKit.isBlank(jobConfig)) {
            return;
        }
        jobProp = PropKit.use(jobConfig).getProperties();
        String jobArray = PropKit.use(jobConfig).get("jobArray");
        if (StrKit.isBlank(jobArray)) {
            return;
        }
        String[] jobArrayList = jobArray.split(",");
        for (String jobName : jobArrayList) {
            jobs.add(createJobBean(jobName));
        }
    }
    private JobBean createJobBean(String key) {
        JobBean job = new JobBean();
        job.setJobGroup(key);
        job.setJobClass(jobProp.getProperty(key + ".job" , ""));
        job.setCronExpression(jobProp.getProperty(key + ".cron" , ""));
        job.setJobDesc(jobProp.getProperty(key + ".desc" , ""));
        return job;
    }
    @Override
    public boolean stop() {
        try {
            scheduler.shutdown();
        } catch (SchedulerException e) {
            e.printStackTrace();
            LogKit.error("", e);
        }
        return true;
    }
}
============ job 类====================
package com.wjme.app.job;
import com.jfinal.kit.HttpKit;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.PropKit;
import com.jfinal.server.undertow.UndertowConfig;
import com.wjme.App;
import com.wjme.app.busi.DataInfo;
import com.wjme.app.util.DES3Util;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AutoIP implements Job {
    Logger log = LoggerFactory.getLogger(getClass());
    private static String currIP = "";
    private String serverPath = PropKit.get("serverPath");
    private String clientPath = PropKit.get("clientPath");
    private int cPort = new UndertowConfig(App.class).getPort();
    private int port =PropKit.getInt("clientPort", cPort);
    private boolean clientRedirect =PropKit.getBoolean("clientPort", false);
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("xxxxx");
        
    }
}
===============JfinalConfig ====================
	/**
	 * 配置插件
	 */
	public void configPlugin(Plugins me) {
		 
			QuartzPlugin quartz = new QuartzPlugin();
			me.add(quartz);
	 
	}
=================quartz.properties  ======================
#开启的任务列表“,”隔开
jobArray = autoip
autoip.job=com.wjme.app.job.AutoIP
autoip.cron= 0/10 * * * * ?
autoip.desc=autoip
#============================================================================
# 配置主要调度程序属性
#============================================================================
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
#============================================================================
# 配置线程池
#============================================================================
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 5
#============================================================================
# 配置任务
#============================================================================
org.quartz.jobStore.misfireThreshold = 1800
org.quartz.scheduler.skipUpdateCheck = true
 
2017-09-30 08:56
@JFinal  建议波总默认多加一些序列化的实现,如
/**
 * 验证码
 */
public class Captcha  类 
在做一些服务化框架和缓存处理时没办法直接用,还需创建子类再实现序列化使用
 
2017-09-28 15:05
@JFinal 哈哈,已采用如下方式:
     public void afterJFinalStart() {
		try {
			JFinal.me().getConstants().setCaptchaCache(new RedisCaptchaCache());
			RedisCaptchaCache.setCaptchaCache(Redis.use("captcha"));
			
		} catch (TemplateModelException e) {
			e.printStackTrace();
		}
	}