shenhao 5 роки тому
батько
коміт
26bdf7d9c7
28 змінених файлів з 1659 додано та 0 видалено
  1. 14 0
      src/main/java/com/ssj/config/TaskConstant.java
  2. 56 0
      src/main/java/com/ssj/config/TaskPoolConfig.java
  3. 79 0
      src/main/java/com/ssj/quartz/config/ConfigureQuartz.java
  4. 13 0
      src/main/java/com/ssj/quartz/dao/JobEntityDao.java
  5. 211 0
      src/main/java/com/ssj/quartz/domian/JobEntity.java
  6. 26 0
      src/main/java/com/ssj/quartz/service/JobEntityService.java
  7. 67 0
      src/main/java/com/ssj/quartz/service/impl/JobEntityServiceImpl.java
  8. 175 0
      src/main/java/com/ssj/quartz/web/JobController.java
  9. 36 0
      src/main/java/com/ssj/rabbitmq/TopicRabbitConsumer.java
  10. 21 0
      src/main/java/com/ssj/service/dao/WxTemplateDao.java
  11. 16 0
      src/main/java/com/ssj/service/dao/WxTemplateInfoDao.java
  12. 34 0
      src/main/java/com/ssj/service/service/impl/WxTemplateInfoServiceImpl.java
  13. 42 0
      src/main/java/com/ssj/service/service/impl/WxTemplateServiceImpl.java
  14. 46 0
      src/main/java/com/ssj/task/BookOverTimeTask.java
  15. 141 0
      src/main/java/com/ssj/task/PushWeeklyTask.java
  16. 52 0
      src/main/java/com/ssj/task/ReadLastFiveDayTask.java
  17. 33 0
      src/main/java/com/ssj/task/ReadMonthReportTask.java
  18. 33 0
      src/main/java/com/ssj/task/ReadYearReportTask.java
  19. 40 0
      src/main/java/com/ssj/task/sz/AnalysisCountAndWeekTask.java
  20. 34 0
      src/main/java/com/ssj/task/sz/DeviceBalanceTask.java
  21. 32 0
      src/main/java/com/ssj/task/sz/MerchantSummaryTask.java
  22. 114 0
      src/main/java/com/ssj/taskasync/SyncSaveAndSendPushTask.java
  23. 62 0
      src/main/java/com/ssj/taskasync/SyncTemplateInfoSaveTask.java
  24. 34 0
      src/main/java/com/ssj/taskasync/SyncTemplateSaveTask.java
  25. 189 0
      src/main/java/com/ssj/util/WxTemplateCacheUtils.java
  26. 22 0
      src/main/resources/application-quartz.properties
  27. 15 0
      src/main/resources/application.properties
  28. 22 0
      src/main/resources/quartz.properties

+ 14 - 0
src/main/java/com/ssj/config/TaskConstant.java

@@ -0,0 +1,14 @@
+package com.ssj.config;
+
+public class TaskConstant {
+
+	
+
+	//临时的key,可以用于删减的
+	public static final String TEMP_KEY="WX_NEWTEMP_List";
+	
+	//长久的key,只要设置了start和end时间的,都会放到这里
+	public static final String LONG_KEY="WX_LONG_List";
+	
+	
+}

+ 56 - 0
src/main/java/com/ssj/config/TaskPoolConfig.java

@@ -0,0 +1,56 @@
+package com.ssj.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+//启动异步
+@EnableAsync
+@Configuration
+class TaskPoolConfig {
+	
+	
+	@Value("${spring.async.task.core-pool-size}")
+	private int corePoolSize;
+
+	@Value("${spring.async.task.max-pool-size}")
+	private int maxPoolSize;
+	
+	@Value("${spring.async.task.queue-capacity}")
+	private int queueCapacity;
+	
+	@Value("${spring.async.task.keep-alive-seconds}")
+	private int keepAliveSeconds;
+	
+
+	//设置Bean的名称不设置的话没有办法在 任务中对应 配置信息
+	@Bean("taskExecutor")
+	public Executor taskExecutor() {
+	      //根据ThreadPoolTaskExecutor 创建建线程池
+	      ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+	      //为线程设置初始的线程数量 5条线程
+	      executor.setCorePoolSize(corePoolSize);
+	      //为线程设置最大的线程数量 10条线程
+	      executor.setMaxPoolSize(maxPoolSize);
+	      //为任务队列设置最大 任务数量
+	      executor.setQueueCapacity(queueCapacity);
+	      //设置 超出初始化线程的 存在时间为60秒
+	      //也就是 如果现有线程数超过5 则会对超出的空闲线程 设置摧毁时间 也就是60秒
+	      executor.setKeepAliveSeconds(keepAliveSeconds);
+	      //设置 线程前缀
+	      executor.setThreadNamePrefix("taskExecutor-");
+
+	      executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+	      //设置在关闭线程池时是否等待任务完成
+	      executor.setWaitForTasksToCompleteOnShutdown(true);
+	      //设置等待终止的秒数
+	      executor.setAwaitTerminationSeconds(60);
+	      //返回设置完成的线程池
+      	return executor;
+	}
+}

+ 79 - 0
src/main/java/com/ssj/quartz/config/ConfigureQuartz.java

@@ -0,0 +1,79 @@
+package com.ssj.quartz.config;
+
+import org.quartz.spi.JobFactory;
+import org.quartz.spi.TriggerFiredBundle;
+import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
+import org.springframework.beans.factory.config.PropertiesFactoryBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+import org.springframework.scheduling.quartz.SpringBeanJobFactory;
+
+import javax.sql.DataSource;
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * Created by EalenXie on 2018/6/4 11:02
+ * Quartz的核心配置类
+ */
+@Configuration
+public class ConfigureQuartz {
+
+    //配置JobFactory
+    @Bean
+    public JobFactory jobFactory(ApplicationContext applicationContext) {
+        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
+        jobFactory.setApplicationContext(applicationContext);
+        return jobFactory;
+    }
+
+    /**
+     * SchedulerFactoryBean这个类的真正作用提供了对org.quartz.Scheduler的创建与配置,并且会管理它的生命周期与Spring同步。
+     * org.quartz.Scheduler: 调度器。所有的调度都是由它控制。
+     * @param dataSource 为SchedulerFactory配置数据源
+     * @param jobFactory 为SchedulerFactory配置JobFactory
+     */
+    @Bean
+    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource, JobFactory jobFactory) throws IOException {
+        SchedulerFactoryBean factory = new SchedulerFactoryBean();
+        //可选,QuartzScheduler启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录
+        factory.setOverwriteExistingJobs(true);
+        factory.setAutoStartup(true); //设置自行启动
+        factory.setDataSource(dataSource);
+        factory.setJobFactory(jobFactory);
+        factory.setQuartzProperties(quartzProperties());
+        return factory;
+    }
+
+    //从quartz.properties文件中读取Quartz配置属性
+    @Bean
+    public Properties quartzProperties() throws IOException {
+        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
+        propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
+        propertiesFactoryBean.afterPropertiesSet();
+        return propertiesFactoryBean.getObject();
+    }
+
+    //配置JobFactory,为quartz作业添加自动连接支持
+    public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
+            ApplicationContextAware {
+        private transient AutowireCapableBeanFactory beanFactory;
+
+        @Override
+        public void setApplicationContext(final ApplicationContext context) {
+            beanFactory = context.getAutowireCapableBeanFactory();
+        }
+
+        @Override
+        protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
+            final Object job = super.createJobInstance(bundle);
+            beanFactory.autowireBean(job);
+            return job;
+        }
+    }
+
+}

+ 13 - 0
src/main/java/com/ssj/quartz/dao/JobEntityDao.java

@@ -0,0 +1,13 @@
+package com.ssj.quartz.dao;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import com.ssj.quartz.domian.JobEntity;
+
+@Repository
+public interface JobEntityDao extends JpaRepository<JobEntity, Long> {
+
+    JobEntity getById(Integer id);
+
+}

+ 211 - 0
src/main/java/com/ssj/quartz/domian/JobEntity.java

@@ -0,0 +1,211 @@
+package com.ssj.quartz.domian;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+/**
+ * 这里个人示例,可自定义相关属性
+ */
+@Entity
+@Table(name = "qrtz_job_entity")
+public class JobEntity implements Serializable {
+
+    /**
+	 * 
+	 */
+	private static final long serialVersionUID = -1913015642129210598L;
+	@Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+	private String jobClassName;   //class
+    private String name;          //job名称
+    private String group;         //job组名
+    private String cron;          //执行的cron
+    private String parameter;     //job的参数
+    private String description;   //job描述信息
+    @Column(name = "vm_param")
+    private String vmParam;       //vm参数
+    @Column(name = "jar_path")
+    private String jarPath;       //job的jar路径
+    private String status;        //job的执行状态,这里我设置为OPEN/CLOSE且只有该值为OPEN才会执行该Job
+
+    public JobEntity() {
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getGroup() {
+        return group;
+    }
+
+    public void setGroup(String group) {
+        this.group = group;
+    }
+
+    public String getCron() {
+        return cron;
+    }
+
+    public void setCron(String cron) {
+        this.cron = cron;
+    }
+
+    public String getParameter() {
+        return parameter;
+    }
+
+    public void setParameter(String parameter) {
+        this.parameter = parameter;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getVmParam() {
+        return vmParam;
+    }
+
+    public void setVmParam(String vmParam) {
+        this.vmParam = vmParam;
+    }
+
+    public String getJarPath() {
+        return jarPath;
+    }
+
+    public void setJarPath(String jarPath) {
+        this.jarPath = jarPath;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getJobClassName() {
+        return jobClassName;
+    }
+
+    public void setJobClassName(String jobClassName) {
+        this.jobClassName = jobClassName;
+    }
+
+    @Override
+    public String toString() {
+        return "JobEntity{" +
+                "id=" + id +
+                ", name='" + name + '\'' +
+                ", group='" + group + '\'' +
+                ", cron='" + cron + '\'' +
+                ", parameter='" + parameter + '\'' +
+                ", description='" + description + '\'' +
+                ", vmParam='" + vmParam + '\'' +
+                ", jarPath='" + jarPath + '\'' +
+                ", status='" + status + '\'' +
+                '}';
+    }
+
+    //新增Builder模式,可选,选择设置任意属性初始化对象
+    public JobEntity(Builder builder) {
+        id = builder.id;
+        jobClassName=builder.jobClassName;
+        name = builder.name;
+        group = builder.group;
+        cron = builder.cron;
+        parameter = builder.parameter;
+        description = builder.description;
+        vmParam = builder.vmParam;
+        jarPath = builder.jarPath;
+        status = builder.status;
+    }
+
+    public static class Builder {
+        private Integer id;
+        private String jobClassName = "";  //jobClassName
+        private String name = "";          //job名称
+        private String group = "";         //job组名
+        private String cron = "";          //执行的cron
+        private String parameter = "";     //job的参数
+        private String description = "";   //job描述信息
+        private String vmParam = "";       //vm参数
+        private String jarPath = "";       //job的jar路径
+        private String status = "";        //job的执行状态,只有该值为OPEN才会执行该Job
+
+        public Builder withId(Integer i) {
+            id = i;
+            return this;
+        }
+
+        public Builder withJobClassName(String j) {
+            jobClassName = j;
+            return this;
+        }
+
+        public Builder withName(String n) {
+            name = n;
+            return this;
+        }
+
+        public Builder withGroup(String g) {
+            group = g;
+            return this;
+        }
+
+        public Builder withCron(String c) {
+            cron = c;
+            return this;
+        }
+
+        public Builder withParameter(String p) {
+            parameter = p;
+            return this;
+        }
+
+        public Builder withDescription(String d) {
+            description = d;
+            return this;
+        }
+
+        public Builder withVMParameter(String vm) {
+            vmParam = vm;
+            return this;
+        }
+
+        public Builder withJarPath(String jar) {
+            jarPath = jar;
+            return this;
+        }
+
+        public Builder withStatus(String s) {
+            status = s;
+            return this;
+        }
+
+        public JobEntity newJobEntity() {
+            return new JobEntity(this);
+        }
+    }
+
+}

+ 26 - 0
src/main/java/com/ssj/quartz/service/JobEntityService.java

@@ -0,0 +1,26 @@
+package com.ssj.quartz.service;
+
+import java.util.List;
+
+import org.quartz.JobDataMap;
+import org.quartz.JobDetail;
+import org.quartz.JobKey;
+import org.quartz.Trigger;
+
+import com.ssj.quartz.domian.JobEntity;
+
+public interface JobEntityService {
+	//通过Id获取Job
+	 public JobEntity getJobEntityById(Integer id);
+	//从数据库中加载获取到所有Job
+	 public List<JobEntity> loadJobs();
+	//获取JobDataMap.(Job参数对象)
+	 public JobDataMap getJobDataMap(JobEntity job) ;
+	  //获取JobDetail,JobDetail是任务的定义,而Job是任务的执行逻辑,JobDetail里会引用一个Job Class来定义
+	 public JobDetail geJobDetail(JobKey jobKey, String description, JobDataMap map) throws ClassNotFoundException;
+	//获取Trigger (Job的触发器,执行规则)
+	 public Trigger getTrigger(JobEntity job);
+	 //获取JobKey,包含Name和Group
+	 public JobKey getJobKey(JobEntity job) ;
+	 
+}

+ 67 - 0
src/main/java/com/ssj/quartz/service/impl/JobEntityServiceImpl.java

@@ -0,0 +1,67 @@
+package com.ssj.quartz.service.impl;
+
+import com.ssj.quartz.dao.JobEntityDao;
+import com.ssj.quartz.domian.JobEntity;
+import com.ssj.quartz.service.JobEntityService;
+import org.quartz.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+@Service
+public class JobEntityServiceImpl implements JobEntityService{
+	@Autowired
+    private JobEntityDao dao;
+	
+	@Override
+	public JobEntity getJobEntityById(Integer id) {
+		return dao.getById(id);
+	}
+
+	@Override
+	public List<JobEntity> loadJobs() {
+		return dao.findAll();
+	}
+
+	@Override
+	public JobDataMap getJobDataMap(JobEntity job) {
+		JobDataMap map = new JobDataMap();
+		map.put("jobClassName", job.getJobClassName());
+		map.put("name", job.getName());
+		map.put("group", job.getGroup());
+		map.put("cronExpression", job.getCron());
+		map.put("parameter", job.getParameter());
+		map.put("JobDescription", job.getDescription());
+		map.put("vmParam", job.getVmParam());
+		map.put("jarPath", job.getJarPath());
+		map.put("status", job.getStatus());
+		return map;
+	}
+
+	@Override
+	public JobDetail geJobDetail(JobKey jobKey, String description,
+			JobDataMap map) throws ClassNotFoundException {
+		String jobClassName=map.getString("jobClassName");
+		Class taskClass = Class.forName(jobClassName);
+		return JobBuilder.newJob(taskClass)
+	                .withIdentity(jobKey)
+	                .withDescription(description)
+	                .setJobData(map)
+	                .storeDurably()
+	                .build();
+	}
+
+	@Override
+	public Trigger getTrigger(JobEntity job) {
+		return TriggerBuilder.newTrigger()
+                .withIdentity(job.getName(), job.getGroup())
+                .withSchedule(CronScheduleBuilder.cronSchedule(job.getCron()))
+                .build();
+	}
+
+	@Override
+	public JobKey getJobKey(JobEntity job) {
+		return JobKey.jobKey(job.getName(), job.getGroup());
+	}
+
+}

+ 175 - 0
src/main/java/com/ssj/quartz/web/JobController.java

@@ -0,0 +1,175 @@
+package com.ssj.quartz.web;
+
+import com.ssj.framework.core.util.ResponseEntity;
+import com.ssj.framework.core.util.SystemResourceLocator;
+import com.ssj.quartz.domian.JobEntity;
+import com.ssj.quartz.service.JobEntityService;
+import com.ssj.service.kmt.arrange.service.KmtArrangeTemplateService;
+import com.ssj.util.WxTemplateCacheUtils;
+import org.quartz.*;
+import org.quartz.impl.matchers.GroupMatcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.PostConstruct;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ */
+@RestController
+@RequestMapping("/job")
+public class JobController{
+    private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    @Autowired
+    private SchedulerFactoryBean schedulerFactoryBean;
+    @Autowired
+    private JobEntityService jobService;
+
+
+    //初始化启动所有的Job
+    @PostConstruct
+    public void initialize() {
+        try {
+            reStartAllJobs();
+            logger.info("INIT SUCCESS");
+        } catch (Exception e) {
+            logger.info("INIT EXCEPTION : " + e.getMessage());
+            e.printStackTrace();
+        }
+    }
+
+
+    //刷新全量模板到redis
+    @RequestMapping("/refresh/wxall")
+    public String refreshWxAll() {
+        String result;
+        try {
+        	WxTemplateCacheUtils.init();
+            result = "SUCCESS";
+        } catch (Exception e) {
+            result = "EXCEPTION : " + e.getMessage();
+        }
+        return "refresh all jobs : " + result;
+    }
+    
+  
+    /**
+     *  手动更新下一个月的日历表的最少人数,指定活泼数,生成饱和量
+     *  activeNum : 活泼数
+     */
+    @RequestMapping("/refresh/active/{activeNum}")
+    public String refreshActive(@PathVariable Integer activeNum) {
+        String result;
+        try {
+    	    KmtArrangeTemplateService kmtArrangeTemplateService = SystemResourceLocator.getBean(KmtArrangeTemplateService.class);
+    	    try {
+    	        logger.info("手动更新下一个月的日历表的最少人数,指定活泼数,生成饱和量.开始");
+    	        kmtArrangeTemplateService.updateKmtArrangeDetailByNextMonth(activeNum);
+    	    } catch (Exception e) {
+    	        logger.error("手动更新下一个月的日历表的最少人数,指定活泼数,生成饱和量.-->"+e.getMessage());
+    	    }finally{
+    	        logger.info("手动更新下一个月的日历表的最少人数,指定活泼数,生成饱和量.结束");
+    	    }
+            result = "SUCCESS";
+        } catch (Exception e) {
+            result = "EXCEPTION : " + e.getMessage();
+        }
+        return "refresh all jobs : " + result;
+    }
+    
+    
+    
+  
+    
+
+    //根据ID重启某个Job
+    @RequestMapping("/refresh/{id}")
+    public String refresh(@PathVariable Integer id) {
+        String result;
+        JobEntity entity = jobService.getJobEntityById(id);
+        if (entity == null) return "error: id is not exist ";
+        TriggerKey triggerKey = new TriggerKey(entity.getName(), entity.getGroup());
+        JobKey jobKey = jobService.getJobKey(entity);
+        Scheduler scheduler = schedulerFactoryBean.getScheduler();
+        try {
+            scheduler.unscheduleJob(triggerKey);
+            scheduler.deleteJob(jobKey);
+            JobDataMap map = jobService.getJobDataMap(entity);
+            JobDetail jobDetail = jobService.geJobDetail(jobKey, entity.getDescription(), map);
+            if (entity.getStatus().equals("OPEN")) {
+                scheduler.scheduleJob(jobDetail, jobService.getTrigger(entity));
+                result = "Refresh Job : " + entity.getName() + "\t jarPath: " + entity.getJarPath() + " success !";
+            } else {
+                result = "Refresh Job : " + entity.getName() + "\t jarPath: " + entity.getJarPath() + " failed ! , " +
+                        "Because the Job status is " + entity.getStatus();
+            }
+        } catch (Exception e) {
+            result = "Error while Refresh " + e.getMessage();
+        }
+        return result;
+    }
+
+
+    //重启数据库中所有的Job
+    @RequestMapping("/refresh/all")
+    public String refreshAll() {
+        String result;
+        try {
+            reStartAllJobs();
+            result = "SUCCESS";
+        } catch (Exception e) {
+            result = "EXCEPTION : " + e.getMessage();
+        }
+        return "refresh all jobs : " + result;
+    }
+
+    /**
+     * 重新启动所有的job
+     */
+    private void reStartAllJobs() throws SchedulerException {
+
+            Scheduler scheduler = schedulerFactoryBean.getScheduler();
+            Set<JobKey> set = scheduler.getJobKeys(GroupMatcher.anyGroup());
+            for (JobKey jobKey : set) {
+                scheduler.deleteJob(jobKey);
+            }
+            for (JobEntity job : jobService.loadJobs()) {
+                try {
+                    logger.info("Job register name : {} , group : {} , cron : {}", job.getName(), job.getGroup(), job.getCron());
+                    JobDataMap map = jobService.getJobDataMap(job);
+                    JobKey jobKey = jobService.getJobKey(job);
+                    JobDetail jobDetail = jobService.geJobDetail(jobKey, job.getDescription(), map);
+                    if (job.getStatus().equals("OPEN")) {
+                        scheduler.scheduleJob(jobDetail, jobService.getTrigger(job));
+                    }else{
+                        logger.info("Job jump name : {} , Because {} status is {}", job.getName(), job.getName(), job.getStatus());
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+
+    }
+    
+    
+    @RequestMapping("/list")
+	 public ResponseEntity list(
+	    		@RequestParam(required = false, defaultValue = "10") int pageSize,
+				@RequestParam(required = false, defaultValue = "1") int pageNo ) throws Exception {
+		 ResponseEntity responseEntity = new ResponseEntity();
+	    Map<String, Object> data = new HashMap<String, Object>();
+		responseEntity.success(data, "获取成功");
+        return responseEntity;
+	 }
+
+
+}

+ 36 - 0
src/main/java/com/ssj/rabbitmq/TopicRabbitConsumer.java

@@ -0,0 +1,36 @@
+package com.ssj.rabbitmq;
+
+import com.ssj.framework.core.rabbitmq.TopicRabbitConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.RabbitHandler;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.alibaba.fastjson.JSONObject;
+import com.ssj.bean.weixin.push.domain.SendTemplateShort;
+
+import com.ssj.service.weixin.push.service.PushTemplateService;
+
+
+public class TopicRabbitConsumer {
+	
+	  private static Logger logger = LoggerFactory.getLogger(TopicRabbitConsumer.class);
+		
+	  @Autowired
+	  private PushTemplateService pushTemplateService;
+	  
+	  @RabbitListener(queues = {TopicRabbitConfig.topic_push_messages_wx},containerFactory = "customContainerFactory")
+	  @RabbitHandler
+	  public void handleMessage(Message message){
+		  logger.info("消息队列开始消费 ....");
+		  SendTemplateShort sendTemplateShort=JSONObject.parseObject(message.getBody(),SendTemplateShort.class);
+		  logger.error("开始消费推送信息队列数据:"+JSONObject.toJSONString(sendTemplateShort));
+		  pushTemplateService.saveAndSendPushWxTemplate(sendTemplateShort);   
+		  logger.info("消息队列完成消费...");
+	  }
+}
+
+

+ 21 - 0
src/main/java/com/ssj/service/dao/WxTemplateDao.java

@@ -0,0 +1,21 @@
+package com.ssj.service.dao;
+
+import com.ssj.bean.weixin.push.domain.TbWxTemplate;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface WxTemplateDao extends JpaRepository<TbWxTemplate, String> {
+
+	@Query(nativeQuery = true, value = " SELECT * FROM `tb_wx_template` t where t.`status`=1  GROUP BY t.template_id_short ORDER BY t.create_time ASC ")
+	public List<TbWxTemplate> queryTbWxTemplate();
+	
+	@Query(nativeQuery = true, value = "SELECT * FROM `tb_wx_template` t where t.template_id_short=?1 ")
+	public List<TbWxTemplate> queryTbWxTemplateIdShort(String templateIdShort);
+	
+	
+
+}

+ 16 - 0
src/main/java/com/ssj/service/dao/WxTemplateInfoDao.java

@@ -0,0 +1,16 @@
+package com.ssj.service.dao;
+
+import java.util.List;
+
+import com.ssj.bean.weixin.push.domain.TbWxTemplateInfo;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+
+
+public interface WxTemplateInfoDao extends JpaRepository<TbWxTemplateInfo, String> {
+
+	
+	@Query(nativeQuery = true, value = "SELECT * FROM `tb_wx_template_info` t where t.template_id_short=?1 ")
+	public List<TbWxTemplateInfo> queryTbWxTemplateInfoByShort(String templateIdShort);
+	
+}

+ 34 - 0
src/main/java/com/ssj/service/service/impl/WxTemplateInfoServiceImpl.java

@@ -0,0 +1,34 @@
+package com.ssj.service.service.impl;
+
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.repository.PagingAndSortingRepository;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.ssj.bean.weixin.push.domain.TbWxTemplateInfo;
+import com.ssj.framework.core.common.service.BaseServiceImpl;
+import com.ssj.service.dao.WxTemplateInfoDao;
+import com.ssj.service.weixin.push.service.WxTemplateInfoService;
+
+
+@Service
+@Transactional
+public class WxTemplateInfoServiceImpl extends BaseServiceImpl<TbWxTemplateInfo, String> implements WxTemplateInfoService {
+
+	@Autowired
+	private WxTemplateInfoDao dao;
+	
+	@Override
+	public PagingAndSortingRepository<TbWxTemplateInfo, String> getDao() {
+		return dao;
+	}
+
+	@Override
+	public List<TbWxTemplateInfo> queryTbWxTemplateInfoByShort(String templateIdShort){
+		return dao.queryTbWxTemplateInfoByShort(templateIdShort);
+	}
+
+}

+ 42 - 0
src/main/java/com/ssj/service/service/impl/WxTemplateServiceImpl.java

@@ -0,0 +1,42 @@
+package com.ssj.service.service.impl;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.repository.PagingAndSortingRepository;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.ssj.bean.weixin.push.domain.TbWxTemplate;
+import com.ssj.framework.core.common.service.BaseServiceImpl;
+import com.ssj.service.dao.WxTemplateDao;
+import com.ssj.service.weixin.push.service.WxTemplateService;
+
+
+@Service
+@Transactional
+public class WxTemplateServiceImpl extends BaseServiceImpl<TbWxTemplate, String> implements WxTemplateService {
+
+	@Autowired
+	private WxTemplateDao dao;
+	
+	@Override
+	public PagingAndSortingRepository<TbWxTemplate, String> getDao() {
+		return dao;
+	}
+
+	@Override
+	public List<TbWxTemplate> queryTbWxTemplate() {
+		return dao.queryTbWxTemplate();
+	}
+
+	@Override
+	public List<TbWxTemplate> queryTbWxTemplateIdShort(String templateIdShort) {
+		// TODO Auto-generated method stub
+		return dao.queryTbWxTemplateIdShort(templateIdShort);
+	}
+	
+	
+	
+
+}

+ 46 - 0
src/main/java/com/ssj/task/BookOverTimeTask.java

@@ -0,0 +1,46 @@
+package com.ssj.task;
+
+
+import com.ssj.framework.core.util.SystemResourceLocator;
+import com.ssj.service.conch.conch.service.IntegralDetailService;
+import com.ssj.service.weixin.library.service.IBookDetailService;
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@DisallowConcurrentExecution
+@Component
+public class BookOverTimeTask implements Job {
+
+    private static Logger logger = LoggerFactory.getLogger(BookOverTimeTask.class);
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext)  {
+
+        //书籍将过期
+        try {
+            IBookDetailService detailService = SystemResourceLocator.getBean(IBookDetailService.class);
+            logger.info("推送书籍将过期任务开始");
+            detailService.sendBookOverMsg();
+        } catch (Exception e) {
+            logger.error("推送书籍将过期任务异常-->"+e.getMessage());
+        }finally{
+            logger.info("推送书籍将过期任务结束");
+        }
+
+        //服务过期60天,积分清0
+        try {
+            IntegralDetailService integralDetailService = SystemResourceLocator.getBean(IntegralDetailService.class);
+            logger.info("服务过期60天积分清0任务开始");
+            integralDetailService.clearTowMonthIntegral();
+        } catch (Exception e) {
+            logger.error("服务过期60天积分清0异常-->"+e.getMessage());
+        }finally{
+            logger.info("服务过期60天积分清0结束");
+        }
+    }
+
+}

+ 141 - 0
src/main/java/com/ssj/task/PushWeeklyTask.java

@@ -0,0 +1,141 @@
+package com.ssj.task;
+
+import com.alibaba.fastjson.JSONObject;
+import com.ssj.bean.weixin.libmy.domain.TbLibWeeklyRecord;
+import com.ssj.bean.weixin.push.domain.SendTemplateShort;
+import com.ssj.framework.basic.utils.DateHelper;
+import com.ssj.framework.core.util.SystemResourceLocator;
+import com.ssj.service.weixin.library.service.ILibSubscribeService;
+import com.ssj.service.weixin.library.service.IOneBookService;
+import com.ssj.service.weixin.library.service.LibWeeklyRecordService;
+import com.ssj.service.weixin.order.service.OrderDetailsService;
+import com.ssj.service.weixin.push.service.PushTemplateService;
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+
+@DisallowConcurrentExecution
+    @Component
+    public class PushWeeklyTask implements Job {
+
+        private static Logger logger = LoggerFactory.getLogger(PushWeeklyTask.class);
+
+        @Override
+        public void execute(JobExecutionContext jobExecutionContext) {
+            try {
+
+                ILibSubscribeService libSubscribeService =  SystemResourceLocator.getBean(ILibSubscribeService.class);
+                OrderDetailsService orderDetailsService =  SystemResourceLocator.getBean(OrderDetailsService.class);
+                IOneBookService oneService =  SystemResourceLocator.getBean(IOneBookService.class);
+                LibWeeklyRecordService libWeeklyRecordService =  SystemResourceLocator.getBean(LibWeeklyRecordService.class);
+                PushTemplateService pushTemplateService= SystemResourceLocator.getBean(PushTemplateService.class);
+
+
+                String weekly=getTimeInterval(new Date());
+                String startTime=weekly.split(",")[0];
+                String endTime= weekly.split(",")[1];
+                String url= SystemResourceLocator.getValue("sys_url")+"/weixin/weekly/weekly_#VIPID#?start_time="+startTime+"&end_time="+endTime;
+                List<Map<String,Object>> borrows= libSubscribeService.queryBorrowByVip(startTime, endTime);
+
+                Map<String,String> data =new HashMap<String, String>();
+                for (Map<String, Object> map : borrows) {
+                    try{
+                        data.clear();
+                        String vip_id=map.get("vip_id").toString();
+                        String user_id=map.get("user_id").toString();
+                        String wx_account=map.get("wx_account").toString();
+                        String child_name=map.get("child_name").toString();
+
+                        Map<String,Object> libVip=libSubscribeService.queryEffectiveByVip(vip_id);
+                        Long subscribenum= libSubscribeService.countSubscribeByVip(vip_id, startTime, endTime);
+                        if(libVip!=null && subscribenum>0){//有效的
+                            Map<String,Object> readMap= libSubscribeService.countWeeklyRead(vip_id, startTime, endTime);
+                            int timeCount=0;
+                            if(readMap.get("time_count")!=null){
+                                timeCount=(int)Double.parseDouble(readMap.get("time_count").toString());//阅读分数
+                            }
+                            Map<String,Object> rankingMap= libSubscribeService.queryRankingByVip(vip_id, startTime, endTime);
+                            double ranking=0;
+                            if(rankingMap.get("rownum")!=null){
+                                ranking=Double.parseDouble(rankingMap.get("rownum").toString());
+                            }
+
+                            Integer count=orderDetailsService.signSubscribCount(libVip.get("lib_id").toString());
+                            double rankingrate=((double)count-ranking)/(double)count*100;
+                            logger.info("rankingrate:"+rankingrate+"  count:"+count+"  ranking:"+ranking);
+                            long borrownum= libSubscribeService.countBorrowByVip(vip_id, startTime, endTime);
+
+                            Map<String, Object> firstMap = oneService.getTjInfo(user_id);
+
+                            data.put("first", child_name+"妈妈/爸爸,您好。您孩子本周阅读报告出炉咯\n");
+                            data.put("keyword1","这周你孩子到馆阅读"+timeCount+"分时长,完成"+firstMap.get("readnum")+"次阅读心得分享,累计借阅"+borrownum+"本图书 。");
+                            data.put("keyword2","你孩子目前的阅读量,在私塾家小会员里面排名处于"+getRankingRateTitle(rankingrate)+",跑赢 "+rankingrate+"% 的小会员,继续加油哦!");
+                            data.put("remark", "\n点击“详情”,即可查看您孩子的阅读周报告。");
+                            String template_id_short=(String) SystemResourceLocator.getValue("sendTemplate104");
+                            //SendTemplate  sendTemplate  =new  SendTemplate(wx_account,templateId,url.replaceAll("#VIPID#", vip_id),data);
+                            //NewsUtil.sendTemplate( tokenManager.getSSJAccessToken(), sendTemplate);
+
+                            SendTemplateShort sendTemplateShort=new SendTemplateShort(wx_account, template_id_short, url.replaceAll("#VIPID#", vip_id), data);
+                            pushTemplateService.savePushWxTemplate(sendTemplateShort);
+
+
+                            TbLibWeeklyRecord record=new TbLibWeeklyRecord();
+                            record.setVipId(vip_id);
+                            record.setStartTime(DateHelper.parseDate(startTime, "yyyy-MM-dd"));
+                            record.setPushTime(new Date());
+                            record.setContent(JSONObject.toJSONString(data));
+                            libWeeklyRecordService.save(record);
+                        }
+                    } catch (Exception e) {
+                        logger.error("任务失败:" + e.getMessage(), e);
+                    }
+                }
+            } catch (Exception e) {
+                logger.error("任务失败:" + e.getMessage(), e);
+            }
+        }
+
+        /**
+         * 根据当前日期获得所在周的日期区间(周一和周日日期)
+         *
+         * @return
+         * @author wuwen
+         * 2017年9月26日11:54:02
+         * @throws
+         */
+        private static String getTimeInterval(Date date) {
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(date);
+            int dayWeek = cal.get(Calendar.DAY_OF_WEEK);// 获得当前日期是一个星期的第几天
+            if (1 == dayWeek) {
+                cal.add(Calendar.DAY_OF_MONTH, -1);
+            }
+            cal.setFirstDayOfWeek(Calendar.MONDAY);
+            int day = cal.get(Calendar.DAY_OF_WEEK);
+            cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day);
+            SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd");
+            String imptimeBegin = sdf.format(cal.getTime());
+            cal.add(Calendar.DATE, 6);
+            String imptimeEnd = sdf.format(cal.getTime());
+            return imptimeBegin + "," + imptimeEnd;
+        }
+
+
+        private static String getRankingRateTitle(double rankingrate) {
+            if(rankingrate>=0 && rankingrate<=59){
+                return "中下游";
+            }else if(rankingrate>=60 && rankingrate<=79){
+                return "中游";
+            }else{
+                return "上游";
+            }
+        }
+
+}

+ 52 - 0
src/main/java/com/ssj/task/ReadLastFiveDayTask.java

@@ -0,0 +1,52 @@
+package com.ssj.task;
+
+import com.ssj.framework.core.util.SystemResourceLocator;
+import com.ssj.service.weixin.library.service.ILibBorrowHisService;
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.Calendar;
+import java.util.Date;
+
+@DisallowConcurrentExecution
+@Component
+public class ReadLastFiveDayTask implements Job {
+
+    private static Logger logger = LoggerFactory.getLogger(ReadLastFiveDayTask.class);
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) {
+        try {
+            logger.info("每月倒数第五天推送提醒给家长");
+            Date date = new Date();
+            Calendar ca = Calendar.getInstance();
+            ca.setTime(date);
+            int days = ca.get(Calendar.DAY_OF_MONTH);
+            int lastDay = ca.getActualMaximum(Calendar.DAY_OF_MONTH);
+            //第五天
+            if(lastDay-days==4){
+                ILibBorrowHisService hisService = SystemResourceLocator.getBean(ILibBorrowHisService.class);
+                hisService.pushReadNoticeToUser();
+            }
+
+        } catch (Exception e) {
+            logger.error("每月倒数第五天推送提醒给家长异常-->"+e.getMessage());
+        }finally{
+            logger.info("每月倒数第五天推送提醒给家长结束");
+        }
+
+    }
+
+    public static void main(String[] args) {
+        Date date = new Date();
+        Calendar ca = Calendar.getInstance();
+        ca.setTime(date);
+        int days = ca.get(Calendar.DAY_OF_MONTH);
+        int lastDay = ca.getActualMaximum(Calendar.DAY_OF_MONTH);
+        System.out.println(lastDay-days);
+    }
+}

+ 33 - 0
src/main/java/com/ssj/task/ReadMonthReportTask.java

@@ -0,0 +1,33 @@
+package com.ssj.task;
+
+import com.ssj.framework.core.util.SystemResourceLocator;
+import com.ssj.service.weixin.library.service.ILibBorrowHisService;
+import com.ssj.service.weixin.library.service.ILibSubscribeService;
+import com.ssj.service.weixin.zuoyb.service.ZuoybStudentBgService;
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@DisallowConcurrentExecution
+@Component
+public class ReadMonthReportTask implements Job {
+
+    private static Logger logger = LoggerFactory.getLogger(ReadMonthReportTask.class);
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) {
+        try {
+            logger.info("每月第一天发送上个月阅读排名结果给家长");
+            ILibBorrowHisService hisService = SystemResourceLocator.getBean(ILibBorrowHisService.class);
+            hisService.pushReadMonthToUser();
+        } catch (Exception e) {
+            logger.error("每月第一天发送上个月阅读排名结果给家长异常-->"+e.getMessage());
+        }finally{
+            logger.info("每月第一天发送上个月阅读排名结果给家长结束");
+        }
+
+    }
+}

+ 33 - 0
src/main/java/com/ssj/task/ReadYearReportTask.java

@@ -0,0 +1,33 @@
+package com.ssj.task;
+
+import com.ssj.framework.core.util.SystemResourceLocator;
+import com.ssj.service.weixin.library.service.ILibBorrowHisService;
+import com.ssj.service.weixin.library.service.ILibSubscribeService;
+import com.ssj.service.weixin.zuoyb.service.ZuoybStudentBgService;
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@DisallowConcurrentExecution
+@Component
+public class ReadYearReportTask implements Job {
+
+    private static Logger logger = LoggerFactory.getLogger(ReadYearReportTask.class);
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) {
+        try {
+            logger.info("1月1日发送上年阅读排名结果给家长");
+            ILibBorrowHisService hisService = SystemResourceLocator.getBean(ILibBorrowHisService.class);
+            hisService.pushReadYearToUser();
+        } catch (Exception e) {
+            logger.error("1月1日发送上年阅读排名结果给家长异常-->"+e.getMessage());
+        }finally{
+            logger.info("1月1日发送上年阅读排名结果给家长结束");
+        }
+
+    }
+}

+ 40 - 0
src/main/java/com/ssj/task/sz/AnalysisCountAndWeekTask.java

@@ -0,0 +1,40 @@
+package com.ssj.task.sz;
+
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import com.ssj.framework.core.util.SystemResourceLocator;
+import com.ssj.service.sys.analysis.service.AnalysisCountService;
+import com.ssj.service.sys.analysis.service.AnalysisWeekService;
+
+@Component
+@DisallowConcurrentExecution
+public class AnalysisCountAndWeekTask implements Job {
+	
+    private static Logger logger = LoggerFactory.getLogger(AnalysisCountAndWeekTask.class);
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext){
+    	
+    	try{
+        	AnalysisCountService analysisCountService = SystemResourceLocator.getBean(AnalysisCountService.class);
+        	logger.info("统计前一天的接口数据开始");
+        	analysisCountService.runTaskAnalysisCount();
+        }catch (Exception e) {
+            logger.error("统计前一天的接口数据异常-->"+e.getMessage());
+        }
+    	
+        try {
+        	AnalysisWeekService analysisWeekService = SystemResourceLocator.getBean(AnalysisWeekService.class);
+            logger.info("统计前一天周的接口数据开始");
+            analysisWeekService.runTaskByAnalysisWeek();
+        } catch (Exception e) {
+            logger.error("统计前一天周的接口数据异常-->"+e.getMessage());
+        }
+
+    }
+}

+ 34 - 0
src/main/java/com/ssj/task/sz/DeviceBalanceTask.java

@@ -0,0 +1,34 @@
+package com.ssj.task.sz;
+
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import com.ssj.framework.core.util.SystemResourceLocator;
+import com.ssj.service.sys.fx.service.DeviceBalanceService;
+
+@Component
+@DisallowConcurrentExecution
+public class DeviceBalanceTask implements Job {
+	
+    private static Logger logger = LoggerFactory.getLogger(DeviceBalanceTask.class);
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext){
+    	DeviceBalanceService deviceBalanceService = SystemResourceLocator.getBean(DeviceBalanceService.class);
+        try {
+            logger.info("有小塾、没小塾统计开始");
+            deviceBalanceService.runCountDeviceBalance(null);
+        } catch (Exception e) {
+            logger.error("有小塾、没小塾统计任务异常-->",e);
+        }finally{
+            logger.info("有小塾、没小塾统计任务结束");
+        }
+    }
+
+	
+
+}

+ 32 - 0
src/main/java/com/ssj/task/sz/MerchantSummaryTask.java

@@ -0,0 +1,32 @@
+package com.ssj.task.sz;
+
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import com.ssj.framework.core.util.SystemResourceLocator;
+import com.ssj.service.sys.fx.service.MerchantService;
+
+@DisallowConcurrentExecution
+@Component
+public class MerchantSummaryTask implements Job{
+
+	private static Logger logger = LoggerFactory.getLogger(MerchantSummaryTask.class);
+	
+	@Override
+	public void execute(JobExecutionContext context) throws JobExecutionException {
+		MerchantService merchantService = SystemResourceLocator.getBean(MerchantService.class);
+		try{
+			logger.error("结算扣币定时任务,00点启动任务....start....");
+			merchantService.runSummaryByMerchant_new();
+			logger.error("结算扣币定时任务,00点启动任务....end....");
+		}catch (Exception e) {
+			logger.error("结算扣币定时任务,00点启动异常-->"+e.getMessage());
+		}
+
+	}
+}

+ 114 - 0
src/main/java/com/ssj/taskasync/SyncSaveAndSendPushTask.java

@@ -0,0 +1,114 @@
+package com.ssj.taskasync;
+
+import java.util.Date;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+import com.alibaba.fastjson.JSONObject;
+import com.ssj.bean.weixin.push.domain.PushTemplate;
+import com.ssj.bean.weixin.push.domain.SendTemplateShort;
+import com.ssj.bean.weixin.push.domain.TbWxTemplate;
+import com.ssj.framework.core.security.manager.TokenManager;
+import com.ssj.framework.core.util.SystemResourceLocator;
+import com.ssj.framework.weixin.util.NewsUtil;
+import com.ssj.service.weixin.push.service.PushTemplateService;
+import com.ssj.util.WxTemplateCacheUtils;
+
+@Component	
+public class SyncSaveAndSendPushTask {
+	
+	protected Logger logger = LoggerFactory.getLogger(this.getClass());
+	
+	@Async("taskExecutor")
+	public void run(SendTemplateShort sendTemplateShort) {
+		logger.error("立即微信推送任务开始---------------");
+		try {
+			TokenManager tokenManager = (TokenManager)SystemResourceLocator.getBean(TokenManager.class,"tokenManager");
+			PushTemplateService pushTemplateService = (PushTemplateService)SystemResourceLocator.getBean(PushTemplateService.class);
+			PushTemplate pushTemplate=null;
+			if(StringUtils.isNotEmpty(sendTemplateShort.getPushTemplateId())){
+				pushTemplate=pushTemplateService.getById(sendTemplateShort.getPushTemplateId());
+				logger.error("查询PushTemplateId:"+sendTemplateShort.getPushTemplateId()+"data:"+JSONObject.toJSONString(pushTemplate));
+			}
+			if(pushTemplate==null){
+				logger.error("pushTemplate为空...");
+				pushTemplate =new PushTemplate();
+				pushTemplate.setClickUrl(sendTemplateShort.getUrl());
+				pushTemplate.setInterVal(sendTemplateShort.getInterVal());
+				pushTemplate.setOpenid(sendTemplateShort.getTouser());
+				pushTemplate.setTopColor(sendTemplateShort.getTopColor());
+				pushTemplate.setTotal(sendTemplateShort.getTotal());
+				pushTemplate.setWxTplSid(sendTemplateShort.getTemplate_id_short());
+				pushTemplate.setContent(JSONObject.toJSONString(sendTemplateShort.getData()));
+				if(sendTemplateShort.getMiniprogram()!=null && StringUtils.isNotEmpty(sendTemplateShort.getMiniprogram().getAppid())){
+					pushTemplate.setMiniprogram(JSONObject.toJSONString(sendTemplateShort.getMiniprogram()));
+				}
+				pushTemplate.setCreateTime(new Date());
+				pushTemplate.setCurTotal(0);
+				pushTemplate.setIsSuccess(0);
+				pushTemplate.setStat(1);
+				pushTemplate.setTryTime(0);
+			}
+			
+			TbWxTemplate tbWxTemplate= WxTemplateCacheUtils.getTbWxTemplate(pushTemplate.getWxTplSid(),null,null);
+			if(StringUtils.isEmpty(pushTemplate.getOpenid())){
+				 pushTemplate.setRemark("OPENID为空,请注意检查来源代码逻辑...");
+				 pushTemplate.setTryTime(pushTemplate.getTryTime()+1);
+			}else if(tbWxTemplate!=null && StringUtils.isNotEmpty(tbWxTemplate.getTemplateId())){
+				try {
+					String msg= NewsUtil.WX_TPL_BODY
+							  	 .replace(NewsUtil.TPL_CODE_OPENID, pushTemplate.getOpenid())
+							  	 .replace(NewsUtil.TPL_CODE_TPLID, tbWxTemplate.getTemplateId())
+					             .replace(NewsUtil.TPL_CODE_URL, StringUtils.isNotEmpty(pushTemplate.getClickUrl())?pushTemplate.getClickUrl():"")
+					             .replace(NewsUtil.TPL_CODE_DATA, pushTemplate.getContent())
+					             .replace(NewsUtil.TPL_CODE_TOPCOLOR, StringUtils.isNotEmpty(pushTemplate.getTopColor())?pushTemplate.getTopColor():"");
+					 if(StringUtils.isNotEmpty(pushTemplate.getMiniprogram())){
+						 msg=msg.replace(NewsUtil.TPL_CODE_MINIPROQRAM_TEXT, NewsUtil.TPL_SUB_MINIPROQRAM_DATA);
+						 msg=msg.replace(NewsUtil.MINIPROQRAM_DATA, pushTemplate.getMiniprogram());
+					 }else{
+						 msg=msg.replace(NewsUtil.TPL_CODE_MINIPROQRAM_TEXT, "");
+					 }
+					 
+					 //再去查询,防止重复推送,定时推送数据锁定一分钟
+					 if(StringUtils.isNotEmpty(pushTemplate.getId())){
+						 pushTemplate=pushTemplateService.getById(pushTemplate.getId());
+						 logger.error("查询pushTemplate对象:"+pushTemplate.getId()+"data:"+JSONObject.toJSONString(pushTemplate));
+					 }
+					 if(pushTemplate.getIsSuccess()==0){
+						 JSONObject result =NewsUtil.sendTemplate(tokenManager.getSSJAccessToken(), msg);
+						 logger.error("[PushTemplateServiceImpl]  WxTplSid: " + pushTemplate.getWxTplSid() + ", result: " + result);
+						 if(result != null && "0".equals(result.getString("errcode"))){
+							 pushTemplate.setIsSuccess(1);
+							 pushTemplate.setSuccessTime(new Date());
+							 pushTemplate.setCurTotal(pushTemplate.getCurTotal()+1); 
+							 pushTemplate.setRemark("");
+						 }else{
+							 pushTemplate.setTryTime(pushTemplate.getTryTime()+1);
+							 pushTemplate.setRemark("errcode:"+result.getString("errcode"));
+						 }
+					 }
+				} catch (Exception e) {
+					 pushTemplate.setTryTime(pushTemplate.getTryTime()+1);
+					 pushTemplate.setRemark("exception:"+e.getMessage());
+				}
+			 }else{
+				 pushTemplate.setRemark("模板池无法得到微信模板ID...");
+				 pushTemplate.setTryTime(pushTemplate.getTryTime()+1);
+			 }
+			pushTemplateService.save(pushTemplate);
+		} catch (Exception e) {
+			e.printStackTrace();
+			logger.error("保存推送信息异常...");
+		}
+		logger.error("立即微信推送任务结束---------------");
+	}
+
+	
+	
+	
+
+}

+ 62 - 0
src/main/java/com/ssj/taskasync/SyncTemplateInfoSaveTask.java

@@ -0,0 +1,62 @@
+package com.ssj.taskasync;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.http.client.utils.DateUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+import com.ssj.bean.weixin.push.domain.TbWxTemplate;
+import com.ssj.bean.weixin.push.domain.TbWxTemplateInfo;
+import com.ssj.framework.core.util.StringUtil;
+import com.ssj.framework.core.util.SystemResourceLocator;
+import com.ssj.framework.weixin.news.bean.Template;
+import com.ssj.framework.weixin.util.NewsUtil;
+import com.ssj.service.weixin.push.service.WxTemplateInfoService;
+
+
+@Component	
+public class SyncTemplateInfoSaveTask {
+	
+	protected Logger logger = LoggerFactory.getLogger(this.getClass());
+	
+	@Async("taskExecutor")
+	public void run(String templateIdShort,TbWxTemplate tbWxTemplate,String accessToken) {
+		
+		synchronized(this){
+			WxTemplateInfoService wxTemplateInfoService = (WxTemplateInfoService)SystemResourceLocator.getBean(WxTemplateInfoService.class);
+		    try {
+		    	if(StringUtil.isNotEmpty(templateIdShort)){
+			    	List<TbWxTemplateInfo> tbWxTemplateInfos= wxTemplateInfoService.queryTbWxTemplateInfoByShort(templateIdShort);
+			    	if(tbWxTemplateInfos==null || tbWxTemplateInfos.size()==0){
+				    	List<Template> templates= NewsUtil.getAllTemplate(accessToken);
+			  		    for (Template template : templates) {
+			  			   if(template.getTemplate_id().equals(tbWxTemplate.getTemplateId())){
+			  				   TbWxTemplateInfo tbWxTemplateInfo=new TbWxTemplateInfo();
+			  				   tbWxTemplateInfo.setContent(template.getContent());
+			  				   tbWxTemplateInfo.setCreateTime(DateUtils.formatDate(new Date(), "yyyy-MM-dd"));
+			  				   tbWxTemplateInfo.setDeputyIndustry(template.getDeputy_industry());
+			  				   tbWxTemplateInfo.setExample(template.getExample());
+			  				   tbWxTemplateInfo.setPrimaryIndustry(template.getTitle());
+			  				   tbWxTemplateInfo.setTemplateIdShort(templateIdShort);
+			  				   tbWxTemplateInfo.setTitle(template.getTitle());
+			  				   wxTemplateInfoService.save(tbWxTemplateInfo);
+			  				   break;
+			  			   }
+			  		   }    
+			    	}
+		    	}
+	        } catch (Exception e) {
+	        	logger.error(" 微信模板明细数据保存,异常---------------");
+	        }
+		}
+		
+	}
+
+	
+	
+
+}

+ 34 - 0
src/main/java/com/ssj/taskasync/SyncTemplateSaveTask.java

@@ -0,0 +1,34 @@
+package com.ssj.taskasync;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+import com.ssj.bean.weixin.push.domain.TbWxTemplate;
+import com.ssj.framework.core.util.SystemResourceLocator;
+import com.ssj.service.weixin.push.service.WxTemplateService;
+
+@Component	
+public class SyncTemplateSaveTask {
+
+	protected Logger logger = LoggerFactory.getLogger(this.getClass());
+	
+	@Async("taskExecutor")
+	public void run(TbWxTemplate tbWxTemplate) {
+		synchronized(this){
+		    try {
+		    	if(tbWxTemplate!=null){
+		    		WxTemplateService wxTemplateService = (WxTemplateService)SystemResourceLocator.getBean(WxTemplateService.class);
+		    		wxTemplateService.save(tbWxTemplate);
+		    	}
+	        } catch (Exception e) {
+	        	logger.error(" 微信模板运行数据保存,异常---------------");
+	        }
+		}
+		
+	}
+
+	
+	
+}

+ 189 - 0
src/main/java/com/ssj/util/WxTemplateCacheUtils.java

@@ -0,0 +1,189 @@
+package com.ssj.util;
+
+import com.alibaba.fastjson.JSONObject;
+import com.ssj.bean.weixin.push.domain.TbWxTemplate;
+import com.ssj.config.TaskConstant;
+import com.ssj.framework.core.security.manager.TokenManager;
+import com.ssj.framework.core.util.RedisUtil;
+import com.ssj.framework.core.util.SystemResourceLocator;
+import com.ssj.framework.weixin.util.NewsUtil;
+import com.ssj.framework.weixin.util.WeixinUtil;
+import com.ssj.service.weixin.push.service.WxTemplateService;
+import com.ssj.taskasync.SyncTemplateInfoSaveTask;
+import com.ssj.taskasync.SyncTemplateSaveTask;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 重构模板池
+ * 2019年4月11日15:00:41
+ * @author wuwen
+ */
+public class WxTemplateCacheUtils {
+	
+	private static Logger logger = LoggerFactory.getLogger(WxTemplateCacheUtils.class);
+	
+	//初始化模板到redis
+	@SuppressWarnings("all")
+	public static synchronized void init() {
+    	WxTemplateService wxTemplateService = (WxTemplateService) SystemResourceLocator.getBean(WxTemplateService.class);
+    	RedisUtil redisUtil= (RedisUtil)SystemResourceLocator.getBean(RedisUtil.class);
+    	List<TbWxTemplate> tbWxTemplates=wxTemplateService.queryTbWxTemplate();
+    	
+    	redisUtil.del(TaskConstant.TEMP_KEY);
+    	redisUtil.del( TaskConstant.LONG_KEY);
+    	//使用List集合,有序。
+    	for (TbWxTemplate tbWxTemplate : tbWxTemplates) {
+    		if(tbWxTemplate.getStartTime()!=null && tbWxTemplate.getEndTime()!=null){
+    			redisUtil.lpush(
+
+        				TaskConstant.LONG_KEY, 
+        				JSONObject.toJSONString(tbWxTemplate));
+    		}else{
+    			redisUtil.lpush(
+
+        				TaskConstant.TEMP_KEY, 
+        				JSONObject.toJSONString(tbWxTemplate));
+        		
+    		}
+		}
+    }
+	
+	//查询redis中所有的模板
+	@SuppressWarnings("all")
+    public static synchronized List<TbWxTemplate> getTbWxTemplates() {
+    	RedisUtil redisUtil= (RedisUtil)SystemResourceLocator.getBean(RedisUtil.class);
+    	List<TbWxTemplate> lists=new ArrayList<TbWxTemplate>();
+    	List<String> longList = redisUtil.lrange(TaskConstant.LONG_KEY,0,-1);
+    	List<String> tempList = redisUtil.lrange(TaskConstant.TEMP_KEY,0,-1);
+    	for (String str : longList) {
+    		lists.add(JSONObject.toJavaObject(JSONObject.parseObject(str),TbWxTemplate.class));
+		}
+    	for (String str : tempList) {
+    		lists.add(JSONObject.toJavaObject(JSONObject.parseObject(str),TbWxTemplate.class));
+		}
+    	return lists;
+	}
+	
+	
+	
+	//查询redis中id的模板
+	@SuppressWarnings("all")
+    public static synchronized TbWxTemplate getTbWxTemplateById(String templateIdShort) {
+    	RedisUtil redisUtil= (RedisUtil)SystemResourceLocator.getBean(RedisUtil.class);
+    	//长久的调用次数高,放前面
+    	List<String> longList = redisUtil.lrange(TaskConstant.LONG_KEY,0,-1);
+    	for (String str : longList) {
+    		JSONObject json=JSONObject.parseObject(str);
+    		if(templateIdShort.equals(json.getString("templateIdShort"))){
+    			return JSONObject.toJavaObject(json,TbWxTemplate.class);
+    		}
+		}
+    	List<String> tempList = redisUtil.lrange(TaskConstant.TEMP_KEY,0,-1);
+    	for (String str : tempList) {
+    		JSONObject json=JSONObject.parseObject(str);
+    		if(templateIdShort.equals(json.getString("templateIdShort"))){
+    			return JSONObject.toJavaObject(json,TbWxTemplate.class);
+    		}
+		}
+    	
+    	return null;
+	}
+	
+	//得到列表的总数量
+	@SuppressWarnings("all")
+    public static synchronized Long getTbWxTemplateSize() {
+    	RedisUtil redisUtil= (RedisUtil)SystemResourceLocator.getBean(RedisUtil.class);
+    	return redisUtil.llen(TaskConstant.LONG_KEY)+redisUtil.llen(TaskConstant.TEMP_KEY);
+	}
+	
+   //查询模板
+   public  static synchronized TbWxTemplate getTbWxTemplate(String templateIdShort,Date startTime,Date endTime) {
+	       //Redis中存在值,直接返回
+		   TbWxTemplate wxTemplate=getTbWxTemplateById(templateIdShort);
+	       if(wxTemplate!=null){
+	    	   wxTemplate.setLastTime(new Date());
+	    	   wxTemplate.setNumber(wxTemplate.getNumber()+1);
+	    	   
+	    	   //更新模板调用数据库,异步任务-----开始
+			   //ThreadPool.getInstance().addTask(new SyncTemplateSaveTask(wxTemplate));
+	    	   SyncTemplateSaveTask syncTemplateSaveTask = (SyncTemplateSaveTask) SystemResourceLocator.getBean(SyncTemplateSaveTask.class);
+	    	   syncTemplateSaveTask.run(wxTemplate);
+			   //更新模板调用数据库,异步任务-----结束
+	    	   return wxTemplate;
+	       }else{//去添加模板
+	    	   /**
+	    	    * 1:如果当前模板池中数量少于25,直接下载添加到池中
+	    	    * 2:如果当前模板池中数量大于等于25,先把池中,上一次生成时间最长的移出池,然后再下载模板添加到Redis池中。
+	    	    */
+	    		return addPoolTbWxTemplate(templateIdShort, startTime, endTime);//添加模板到池中
+	       }  
+    }
+    
+   //在list中最右边删除一个,再从左边添加一个,返回添加值
+    private  static synchronized TbWxTemplate addPoolTbWxTemplate(String templateIdShort,Date startTime,Date endTime){
+    	   TokenManager tokenManager = (TokenManager)SystemResourceLocator.getBean(TokenManager.class);  
+    	   String accessToken=tokenManager.getSSJAccessToken();
+    	   WxTemplateService wxTemplateService = (WxTemplateService)SystemResourceLocator.getBean(WxTemplateService.class);
+    	   RedisUtil redisUtil= (RedisUtil)SystemResourceLocator.getBean(RedisUtil.class);
+    	   
+    	   //如果当前的数据大于25条,先删最右边的
+    	   Long countNum=getTbWxTemplateSize();
+    	   logger.info("当前模板数量为"+countNum+"...");
+		   if(countNum>=25){
+			  logger.info("当前模板数量为25,开始启动删除模板任务");
+			  //通过key从list尾部删除一个value,并返回该元素 
+			  String jsonStr=redisUtil.rpop(TaskConstant.TEMP_KEY);
+			  TbWxTemplate temp=JSONObject.toJavaObject(JSONObject.parseObject(jsonStr), TbWxTemplate.class);
+			  JSONObject reqObj= NewsUtil.delTemplate(accessToken,temp.getTemplateId());
+   		      logger.info("当前模板数量为25,开始启动删除模板任务,结束返回值:"+reqObj.toJSONString());
+   		      if("0".equals(reqObj.get("errcode").toString())){
+   		    	  temp.setStatus(2);
+   		    	  wxTemplateService.save(temp); 
+   		      }
+   	       }  
+		   
+		   TbWxTemplate tbWxTemplate=null;
+    	   String templateId=NewsUtil.getTemplate(accessToken, templateIdShort);//添加模板ID   
+    	   if(StringUtils.isNotEmpty(templateId)){
+    		       tbWxTemplate=new TbWxTemplate();
+    		       String keyType=TaskConstant.TEMP_KEY;
+				   tbWxTemplate.setAppid(WeixinUtil.APPID);
+				   tbWxTemplate.setLastTime(new Date());
+				   tbWxTemplate.setStatus(1);
+				   tbWxTemplate.setTemplateId(templateId);
+				   tbWxTemplate.setTemplateIdShort(templateIdShort);
+				   tbWxTemplate.setCreateTime(new Date());
+				   tbWxTemplate.setNumber(1);
+				   if(startTime!=null && endTime!=null){
+			    	  tbWxTemplate.setStartTime(startTime);
+			    	  tbWxTemplate.setEndTime(endTime);
+			    	  keyType=TaskConstant.LONG_KEY;
+				   }
+				   tbWxTemplate=wxTemplateService.save(tbWxTemplate);//保存到数据,得到id
+				   
+				   //开始操作redis
+				   //通过key向list头部添加字符串
+				   redisUtil.lpush(
+						   keyType,
+						   JSONObject.toJSONString(tbWxTemplate));
+				
+				   //添加数据库明细数据,异步任务-----开始
+				   //ThreadPool.getInstance().addTask(new SyncTemplateInfoSaveTask(templateIdShort,tbWxTemplate,accessToken));
+				   
+				   SyncTemplateInfoSaveTask syncTemplateInfoSaveTask = (SyncTemplateInfoSaveTask) SystemResourceLocator.getBean(SyncTemplateInfoSaveTask.class);
+				   syncTemplateInfoSaveTask.run(templateIdShort,tbWxTemplate,accessToken);
+				   
+				   
+				   //添加数据库明细数据,异步任务-----结束
+    	    }
+		   return tbWxTemplate;
+    }
+    
+
+}

+ 22 - 0
src/main/resources/application-quartz.properties

@@ -0,0 +1,22 @@
+#ID设置为自动获取 每一个必须不同 (所有调度器实例中是唯一的)
+org.quartz.scheduler.instanceId=AUTO
+#指定调度程序的主线程是否应该是守护线程
+org.quartz.scheduler.makeSchedulerThreadDaemon=true
+#ThreadPool实现的类名
+org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
+#ThreadPool配置线程守护进程
+org.quartz.threadPool.makeThreadsDaemons=true
+#线程数量
+org.quartz.threadPool.threadCount:40
+#线程优先级
+org.quartz.threadPool.threadPriority:5
+#数据保存方式为持久化
+org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
+#StdJDBCDelegate说明支持集群
+org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
+#quartz内部表的前缀
+org.quartz.jobStore.tablePrefix=QRTZ_
+#是否加入集群
+org.quartz.jobStore.isClustered=true
+#容许的最大作业延长时间
+org.quartz.jobStore.misfireThreshold=25000

+ 15 - 0
src/main/resources/application.properties

@@ -13,3 +13,18 @@ spring.thymeleaf.encoding=UTF-8
 spring.thymeleaf.servlet.content-type=text/html
 spring.thymeleaf.cash=false
 debug=true
+
+
+#//为线程设置初始的线程数量 5条线程
+spring.async.task.core-pool-size=50
+#//为线程设置最大的线程数量 10条线程
+spring.async.task.max-pool-size=1000
+#//为任务队列设置最大 任务数量
+spring.async.task.queue-capacity=2000
+#//设置 超出初始化线程的 存在时间为60秒 //也就是 如果现有线程数超过5 则会对超出的空闲线程 设置摧毁时间 也就是60秒
+spring.async.task.keep-alive-seconds=180 
+
+spring.mail.host=smtp.sharingschool.com
+spring.mail.username=crm@sharingschool.com
+spring.mail.password=zhidian@123
+spring.mail.default-encoding=UTF-8

+ 22 - 0
src/main/resources/quartz.properties

@@ -0,0 +1,22 @@
+#ID设置为自动获取 每一个必须不同 (所有调度器实例中是唯一的)
+org.quartz.scheduler.instanceId=AUTO
+#指定调度程序的主线程是否应该是守护线程
+org.quartz.scheduler.makeSchedulerThreadDaemon=true
+#ThreadPool实现的类名
+org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
+#ThreadPool配置线程守护进程
+org.quartz.threadPool.makeThreadsDaemons=true
+#线程数量
+org.quartz.threadPool.threadCount:20
+#线程优先级
+org.quartz.threadPool.threadPriority:5
+#数据保存方式为持久化
+org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
+#StdJDBCDelegate说明支持集群
+org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
+#quartz内部表的前缀
+org.quartz.jobStore.tablePrefix=QRTZ_
+#是否加入集群
+org.quartz.jobStore.isClustered=true
+#容许的最大作业延长时间
+org.quartz.jobStore.misfireThreshold=25000