рдлрд┐рд░ рд╕реЗ рдирдорд╕реНрдХрд╛рд░ред рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдкрд╛рдареНрдпрдХреНрд░рдо рдХреЗ рдЫрд╛рддреНрд░реЛрдВ рдХреЗ рд▓рд┐рдП "рдбреЗрд╡рд▓рдкрд░ рдСрди рдж рд╕реНрдкреНрд░рд┐рдВрдЧ рдлреНрд░реЗрдорд╡рд░реНрдХ" рдиреЗ рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рд▓реЗрдЦ рдХрд╛ рдЕрдиреБрд╡рд╛рдж рддреИрдпрд╛рд░ рдХрд┐рдпрд╛ред
рдореЗрд░реЗ рд▓реЗрдЦ
"рдмрдЪрд╛рд╡ рдХреЗ рд▓рд┐рдП рд╡рд┐рдирд┐рд░реНрджреЗрд╢реЛрдВ" рдореЗрдВ, рдореИрдВрдиреЗ рджрд┐рдЦрд╛рдпрд╛ рдХрд┐ рдЖрдк RESTful API рдореЗрдВ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдХреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдкреНрд░рд┐рдВрдЧ рдмреВрдЯ рдореЗрдВ JPA рд╕реНрдкреЗрд╕рд┐рдлрд┐рдХреЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдлрд┐рд░ рд▓реЗрдЦ
"рдЙрди рд╡рд┐рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг" рдореЗрдВ рдпрд╣ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рдХрд┐ рдЗрди рд╕рдорд╛рди рд╡рд┐рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХреИрд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рдПред
рдЕрдЧрд▓реЗ рдЪрд░рдг рдореЗрдВ, рдореИрдВрдиреЗ рдпрд╣ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ рдХрд┐ рдПрдХ рдХрд╛рд░реНрдп рд╢реЗрдбреНрдпреВрд▓рд░ рдХреЛ рдЙрд╕реА рд╕реНрдкреНрд░рд┐рдВрдЧ рдмреВрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдХреИрд╕реЗ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдПред
рдХреНрд╡рд╛рд░реНрдЯреНрдЬ рдЯрд╛рд╕реНрдХ рд╢реЗрдбреНрдпреВрд▓рд░
рд╕реНрдкреНрд░рд┐рдВрдЧ рдЯреАрдо рд╕рд░рд▓ рдорд╛рд╡реЗрди рдирд┐рд░реНрднрд░рддрд╛ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╡рд┐рднрд┐рдиреНрди рд╕реНрдкреНрд░рд┐рдВрдЧ рдмреВрдЯ рд╕реНрдЯрд╛рд░реНрдЯрд░ рдкреНрд▓рдЧрдЗрдиреНрд╕ рдкреНрд░рджрд╛рди рдХрд░рдХреЗ рдЬрд╛рд╡рд╛ рд╡рд┐рдХрд╛рд╕ рдХреА рд╕реБрд╡рд┐рдзрд╛ рдЬрд╛рд░реА рд░рдЦрддреА рд╣реИред
рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ
рдХреНрд╡рд╛рд░реНрдЯреНрдЬ рд╢реЗрдбреНрдпреВрд▓рд░ рд╕реНрдЯрд╛рд░реНрдЯрд░ рдкрд░ рдзреНрдпрд╛рди рдХреЗрдВрджреНрд░рд┐рдд рдХрд░реВрдВрдЧрд╛, рдЬрд┐рд╕реЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдирд┐рд░реНрднрд░рддрд╛ рдХреЗ рд╕рд╛рде рд╕реНрдкреНрд░рд┐рдВрдЧ рдмреВрдЯ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ рдФрд░
рдпрд╣рд╛рдВ рд╡рд░реНрдгрд┐рдд
рд╣реИ ред рдЖрдк
рдпрд╣рд╛рдВ рд╡рд░реНрддрдорд╛рди рд╕реНрдкреНрд░рд┐рдВрдЧ рдмреВрдЯ рд╕реНрдЯрд╛рд░реНрдЯрд░ рдХреА рдкреВрд░реА рд╕реВрдЪреА рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВред
рд╕рдорд╛рдпреЛрдЬрди
рдХрд╛рдо рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП
рдбреЗрд╡рд┐рдб рдХрд┐рд╕реНрд╕рд╛ рджреНрд╡рд╛рд░рд╛ , рдкрд╣рд▓рд╛ рдХрджрдо рдХреНрд╡рд╛рд░реНрдЯреНрдЬ рдиреМрдХрд░рд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╕реНрд╡рдд: рдЬреЛрдбрд╝рдиреЗ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИ:
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; } }
рдЕрдЧрд▓рд╛, рдореВрд▓ рдХреНрд╡рд╛рд░реНрдЯреНрдЬ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдЬреЛрдбрд╝реЗрдВ:
@Configuration public class QuartzConfig { private ApplicationContext applicationContext; private DataSource dataSource; public QuartzConfig(ApplicationContext applicationContext, DataSource dataSource) { this.applicationContext = applicationContext; this.dataSource = dataSource; } @Bean public SpringBeanJobFactory springBeanJobFactory() { AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory(); jobFactory.setApplicationContext(applicationContext); return jobFactory; } @Bean public SchedulerFactoryBean scheduler(Trigger... triggers) { SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean(); Properties properties = new Properties(); properties.setProperty("org.quartz.scheduler.instanceName", "MyInstanceName"); properties.setProperty("org.quartz.scheduler.instanceId", "Instance1"); schedulerFactory.setOverwriteExistingJobs(true); schedulerFactory.setAutoStartup(true); schedulerFactory.setQuartzProperties(properties); schedulerFactory.setDataSource(dataSource); schedulerFactory.setJobFactory(springBeanJobFactory()); schedulerFactory.setWaitForJobsToCompleteOnShutdown(true); if (ArrayUtils.isNotEmpty(triggers)) { schedulerFactory.setTriggers(triggers); } return schedulerFactory; } }
рдЖрдк рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рдЧреБрдгреЛрдВ рдХреЛ
scheduler()
рд╡рд┐рдзрд┐ рд╕реЗ рдмрд╛рд╣рд░ рд░рдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ рд╣реИред
рдлрд┐рд░ рд╕реНрдерд┐рд░ рддрд░реАрдХреЗ рдЬреЛрдбрд╝реЗ рдЬрд╛рддреЗ рд╣реИрдВ рдЬреЛ рдХрд╛рд░реНрдп рдФрд░ рдЯреНрд░рд┐рдЧрд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░реЛрдЧреНрд░рд╛рдореЗрдЯрд┐рдХ рддрд░реАрдХрд╛ рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВ:
@Slf4j @Configuration public class QuartzConfig { ... static SimpleTriggerFactoryBean createTrigger(JobDetail jobDetail, long pollFrequencyMs, String triggerName) { log.debug("createTrigger(jobDetail={}, pollFrequencyMs={}, triggerName={})", jobDetail.toString(), pollFrequencyMs, triggerName); SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean(); factoryBean.setJobDetail(jobDetail); factoryBean.setStartDelay(0L); factoryBean.setRepeatInterval(pollFrequencyMs); factoryBean.setName(triggerName); factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY); factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT); return factoryBean; } static CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, String cronExpression, String triggerName) { log.debug("createCronTrigger(jobDetail={}, cronExpression={}, triggerName={})", jobDetail.toString(), cronExpression, triggerName);
createJobDetail()
рд╡рд┐рдзрд┐ рдХрд╛рд░реНрдп рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд░рд▓ рдФрд░ рдЙрдкрдпреЛрдЧреА рд╡рд┐рдзрд┐ рд╣реИред
рдЯреНрд░рд┐рдЧрд░реНрд╕ рдХреЗ рд▓рд┐рдП рджреЛ рд╡рд┐рдХрд▓реНрдк рд╣реИрдВ: CRON рдФрд░ рд╕рд░рд▓ рдЯреНрд░рд┐рдЧрд░реНрд╕ рдкрд░ рдЖрдзрд╛рд░рд┐рддред
рд╕реЗрд╡рд╛рдПрдВ
рдХреНрд╡рд╛рд░реНрдЯреНрдЬ рдмреЗрд╕ рд╢реЗрдбреНрдпреВрд▓рд░ рдЕрдм рд╣рдорд╛рд░реЗ рд╕реНрдкреНрд░рд┐рдВрдЧ рдмреВрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдХрд╛рд░реНрдп рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИред рдЕрдЧрд▓рд╛, рд╣рдо рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рдХреБрдЫ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдПрдВрдЧреЗ рдЬреЛ рдХрд┐ рдЕрдиреБрд╕реВрдЪрдХ рджреНрд╡рд╛рд░рд╛ рд▓реЙрдиреНрдЪ рдХрд┐рдП рдЬрд╛рдПрдВрдЧреЗред
рдкрд╣рд▓реА рд╕реЗрд╡рд╛ рд╕рд░рд▓ рд╕рджрд╕реНрдпрддрд╛ рдЖрдБрдХрдбрд╝реЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддреА рд╣реИред рдпрджрд┐ рдЖрдкрдХреЛ рдпрд╛рдж рд╣реИ, рддреЛ рдореВрд▓ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдЙрджрд╛рд╣рд░рдг рдПрдХ рдлрд┐рдЯрдиреЗрд╕ рдХреНрд▓рдм рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдерд╛ред рдореЗрдВ
MemberService
рд╡рд░реНрдЧ
MemberService
рдмрдирд╛рдиреЗ
memberStats()
рд╡рд┐рдзрд┐:
public void memberStats() { List<Member> members = memberRepository.findAll(); int activeCount = 0; int inactiveCount = 0; int registeredForClassesCount = 0; int notRegisteredForClassesCount = 0; for (Member member : members) { if (member.isActive()) { activeCount++; if (CollectionUtils.isNotEmpty(member.getMemberClasses())) { registeredForClassesCount++; } else { notRegisteredForClassesCount++; } } else { inactiveCount++; } } log.info("Member Statics:"); log.info("=============="); log.info("Active member count: {}", activeCount); log.info(" - Registered for Classes count: {}", registeredForClassesCount); log.info(" - Not registered for Classes count: {}", notRegisteredForClassesCount); log.info("Inactive member count: {}", inactiveCount); log.info("=========================="); }
рдлрд┐рдЯрдиреЗрд╕ рдХреНрд▓рдм рдХрдХреНрд╖рд╛рдУрдВ рдореЗрдВ рд░реБрдЪрд┐рдпреЛрдВ рдХреЛ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП,
classStats()
рдПрдХ
classStats()
рд╡рд┐рдзрд┐
classStats()
:
public void classStats() { List<MemberClass> memberClasses = classRepository.findAll(); Map<String, Integer> memberClassesMap = memberClasses .stream() .collect(Collectors.toMap(MemberClass::getName, c -> 0)); List<Member> members = memberRepository.findAll(); for (Member member : members) { if (CollectionUtils.isNotEmpty(member.getMemberClasses())) { for (MemberClass memberClass : member.getMemberClasses()) { memberClassesMap.merge(memberClass.getName(), 1, Integer::sum); } } } log.info("Class Statics:"); log.info("============="); memberClassesMap.forEach((k,v) -> log.info("{}: {}", k, v)); log.info("=========================="); }
рдХрд╛рд░реНрдп
рд╕реЗрд╡рд╛ рдХреЛрдб рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЙрдкрдпреБрдХреНрдд рдХрд╛рд░реНрдп рдмрдирд╛рдирд╛ рд╣реЛрдЧрд╛ред
MemberService
рдореИрдВрдиреЗ рдПрдХ
MemberStatsJob
рдЬреЙрдм
MemberStatsJob
рдмрдирд╛рдИ:
@Slf4j @Component @DisallowConcurrentExecution public class MemberStatsJob implements Job { @Autowired private MemberService memberService; @Override public void execute(JobExecutionContext context) { log.info("Job ** {} ** starting @ {}", context.getJobDetail().getKey().getName(), context.getFireTime()); memberService.memberStats(); log.info("Job ** {} ** completed. Next job scheduled @ {}", context.getJobDetail().getKey().getName(), context.getNextFireTime()); } }
MemberClassService
рд╕реЗрд╡рд╛ рдХреЗ рд▓рд┐рдП,
MemberClassService
рд╡рд░реНрдЧ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдерд╛:
@Slf4j @Component @DisallowConcurrentExecution public class MemberClassStatsJob implements Job { @Autowired MemberClassService memberClassService; @Override public void execute(JobExecutionContext context) { log.info("Job ** {} ** starting @ {}", context.getJobDetail().getKey().getName(), context.getFireTime()); memberClassService.classStats(); log.info("Job ** {} ** completed. Next job scheduled @ {}", context.getJobDetail().getKey().getName(), context.getNextFireTime()); } }
рдХрд╛рд░реНрдп рдЕрдиреБрд╕реВрдЪреА
рдЗрд╕ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ, рд╣рдо рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдХрд┐ рд╕реНрдкреНрд░рд┐рдВрдЧ рдмреВрдЯ рд╕рд░реНрд╡рд░ рд╢реБрд░реВ рд╣реЛрдиреЗ рдкрд░ рд╕рднреА рдХрд╛рд░реНрдп рд╢реЗрдбреНрдпреВрд▓ рдХрд┐рдП рдЬрд╛рдПрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ
QuartzSubmitJobs
рд╡рд░реНрдЧ рдмрдирд╛рдпрд╛, рдЬрд┐рд╕рдореЗрдВ рдЪрд╛рд░ рд╕рд░рд▓ рддрд░реАрдХреЗ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред рджреЛ рд╡рд┐рдзрд┐рдпрд╛рдБ рдирдП рдХрд╛рд░реНрдп рдмрдирд╛рддреА рд╣реИрдВ, рдФрд░ рджреЛ рд╡рд┐рдзрд┐рдпрд╛рдБ рд╕рдВрдЧрдд рдЯреНрд░рд┐рдЧрд░ рдмрдирд╛рддреА рд╣реИрдВред
@Configuration public class QuartzSubmitJobs { private static final String CRON_EVERY_FIVE_MINUTES = "0 0/5 * ? * * *"; @Bean(name = "memberStats") public JobDetailFactoryBean jobMemberStats() { return QuartzConfig.createJobDetail(MemberStatsJob.class, "Member Statistics Job"); } @Bean(name = "memberStatsTrigger") public SimpleTriggerFactoryBean triggerMemberStats(@Qualifier("memberStats") JobDetail jobDetail) { return QuartzConfig.createTrigger(jobDetail, 60000, "Member Statistics Trigger"); } @Bean(name = "memberClassStats") public JobDetailFactoryBean jobMemberClassStats() { return QuartzConfig.createJobDetail(MemberClassStatsJob.class, "Class Statistics Job"); } @Bean(name = "memberClassStatsTrigger") public CronTriggerFactoryBean triggerMemberClassStats(@Qualifier("memberClassStats") JobDetail jobDetail) { return QuartzConfig.createCronTrigger(jobDetail, CRON_EVERY_FIVE_MINUTES, "Class Statistics Trigger"); } }
рд╕реНрдкреНрд░рд┐рдВрдЧ рдмреВрдЯ рд▓реЙрдиреНрдЪ рдХрд░реЗрдВ
рдЬрдм рд╕рдм рдХреБрдЫ рддреИрдпрд╛рд░ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЖрдк рд╕реНрдкреНрд░рд┐рдВрдЧ рдмреВрдЯ рд╕рд░реНрд╡рд░ рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдХреНрд╡рд╛рд░реНрдЯреНрдЬ рдЖрд░рдВрднреАрдХрд░рдг рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ:
2019-07-14 14:36:51.651 org.quartz.impl.StdSchedulerFactory : Quartz scheduler 'MyInstanceName' initialized from an externally provided properties instance. 2019-07-14 14:36:51.651 org.quartz.impl.StdSchedulerFactory : Quartz scheduler version: 2.3.0 2019-07-14 14:36:51.651 org.quartz.core.QuartzScheduler : JobFactory set to: com.gitlab.johnjvester.jpaspec.config.AutowiringSpringBeanJobFactory@79ecc507 2019-07-14 14:36:51.851 ossconcurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2019-07-14 14:36:51.901 aWebConfiguration$JpaWebMvcConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning 2019-07-14 14:36:52.051 ossquartz.SchedulerFactoryBean : Starting Quartz Scheduler now 2019-07-14 14:36:52.054 ossquartz.LocalDataSourceJobStore : Freed 0 triggers from 'acquired' / 'blocked' state. 2019-07-14 14:36:52.056 ossquartz.LocalDataSourceJobStore : Recovering 0 jobs that were in-progress at the time of the last shut-down. 2019-07-14 14:36:52.056 ossquartz.LocalDataSourceJobStore : Recovery complete. 2019-07-14 14:36:52.056 ossquartz.LocalDataSourceJobStore : Removed 0 'complete' triggers. 2019-07-14 14:36:52.058 ossquartz.LocalDataSourceJobStore : Removed 0 stale fired job entries. 2019-07-14 14:36:52.058 org.quartz.core.QuartzScheduler : Scheduler MyInstanceName_$_Instance1 started.
рдФрд░
memberStats()
рдЪрд▓ рд░рд╣рд╛ рд╣реИ
memberStats()
рдиреМрдХрд░реА:
2019-07-14 14:36:52.096 cgjjpaspec.jobs.MemberStatsJob : Job ** Member Statistics Job ** starting @ Sun Jul 14 14:36:52 EDT 2019 2019-07-14 14:36:52.217 cgjjpaspec.service.MemberService : Member Statics: 2019-07-14 14:36:52.217 cgjjpaspec.service.MemberService : ============== 2019-07-14 14:36:52.217 cgjjpaspec.service.MemberService : Active member count: 7 2019-07-14 14:36:52.217 cgjjpaspec.service.MemberService : - Registered for Classes count: 6 2019-07-14 14:36:52.217 cgjjpaspec.service.MemberService : - Not registered for Classes count: 1 2019-07-14 14:36:52.217 cgjjpaspec.service.MemberService : Inactive member count: 3 2019-07-14 14:36:52.217 cgjjpaspec.service.MemberService : ========================== 2019-07-14 14:36:52.219 cgjjpaspec.jobs.MemberStatsJob : Job ** Member Statistics Job ** completed. Next job scheduled @ Sun Jul 14 14:37:51 EDT 2019
рдФрд░ рдлрд┐рд░
classStats()
рдиреМрдХрд░реА рдХрд░ рд░рд╣реЗ рд╣реИрдВ:
2019-07-14 14:40:00.006 cgjjpaspec.jobs.MemberClassStatsJob : Job ** Class Statistics Job ** starting @ Sun Jul 14 14:40:00 EDT 2019 2019-07-14 14:40:00.021 cgjjservice.MemberClassService : Class Statics: 2019-07-14 14:40:00.022 cgjjservice.MemberClassService : ============= 2019-07-14 14:40:00.022 cgjjservice.MemberClassService : Tennis: 4 2019-07-14 14:40:00.022 cgjjservice.MemberClassService : FitCore 2000: 3 2019-07-14 14:40:00.022 cgjjservice.MemberClassService : Spin: 2 2019-07-14 14:40:00.022 cgjjservice.MemberClassService : Swimming: 4 2019-07-14 14:40:00.022 cgjjservice.MemberClassService : New Class: 0 2019-07-14 14:40:00.022 cgjjservice.MemberClassService : Basketball: 2 2019-07-14 14:40:00.022 cgjjservice.MemberClassService : ========================== 2019-07-14 14:40:00.022 cgjjpaspec.jobs.MemberClassStatsJob : Job ** Class Statistics Job ** completed. Next job scheduled @ Sun Jul 14 14:45:00 EDT 2019
рдирд┐рд╖реНрдХрд░реНрд╖
рдЙрдкрд░реЛрдХреНрдд рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдореИрдВрдиреЗ рд╕реНрдкреНрд░рд┐рдВрдЧ рдмреВрдЯ рдкрд░ рдПрдХ рдореМрдЬреВрджрд╛ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдФрд░ рдмрд╣реБрдд рдкреНрд░рдпрд╛рд╕ рдХреЗ рдмрд┐рдирд╛ рдЗрд╕рдореЗрдВ рдХреНрд╡рд╛рд░реНрдЯреНрдЬ рдЕрдиреБрд╕реВрдЪрдХ рдХреЛ рдЬреЛрдбрд╝рд╛ред рдореИрдВрдиреЗ рд╕реЗрд╡рд╛ рдкрджреНрдзрддрд┐рдпрд╛рдВ рдмрдирд╛рдИрдВ рдЬреЛ рд╕рд░рд▓ рдбреЗрдЯрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рддреА рдереАрдВред рдЗрди рд╕реЗрд╡рд╛ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдиреМрдХрд░реА рд╡рд░реНрдЧреЛрдВ рджреНрд╡рд╛рд░рд╛ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдЕрдВрдд рдореЗрдВ, рдиреМрдХрд░рд┐рдпреЛрдВ рдФрд░ рдЯреНрд░рд┐рдЧрд░реНрд╕ рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред
рдкреВрд░реНрдг рд╕реНрд░реЛрдд рдХреЛрдб
рдпрд╣рд╛рдВ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛
рд╣реИ ред
рдЕрдЧрд▓реЗ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ рджрд┐рдЦрд╛рдКрдВрдЧрд╛ рдХрд┐ рдХреНрд╡рд╛рд░реНрдЯреНрдЬ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХреА рдЬрд╛рдирдХрд╛рд░реА рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ RESTful API рдХреИрд╕реЗ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдПред