복붙노트

[SPRING] 실시간 통지 전자 메일을 구현하기위한 Quartz와의 Full Spring 통합

SPRING

실시간 통지 전자 메일을 구현하기위한 Quartz와의 Full Spring 통합

저는 현재 사용자가 약속을 잡을 수있는 스프링 부트 응용 프로그램을 개발 중입니다. 따라서 기본적으로 약속에는 startDateTime 및 endDateTime 필드와 전자 메일이 있습니다. 약속을 작성하면 MySql 데이터베이스의 약속 테이블에 새로운 행이 추가됩니다.

내가하고 싶은 일은 데이터베이스에 전자 메일로 정의 된 startDateTime의 한 시간 전에 사용자에게 알리는 것입니다. 솔루션을 찾았지만 찾을 수 없습니다. 나는 일자리 (스프링 배치)가이 일을 할 수 있다는 것을 알았지 만, 일자리가 주파수 수표 (일, 주, 달)에 의존한다는 것은 실시간 알림이라는 것입니다. 이러한 작업을 실현하는 솔루션에 대한 도움이나 안내가 환영 받는다.

인사말

해결법

  1. ==============================

    1.석영과 같은 스케줄 라이브러리를 사용하여 Spring 프레임 워크와 쉽게 통합 할 수 있습니다.

    석영과 같은 스케줄 라이브러리를 사용하여 Spring 프레임 워크와 쉽게 통합 할 수 있습니다.

    데이터베이스에 약속이 저장되면 원하는 시간 (예 : 시작 날짜 1 시간 전) 동안 "이메일 전송"작업이 예약됩니다.

    "send-email"작업은 org.quartz.Job을 구현해야하며, 특히 Autowired SendEmailService 구현을 사용할 수있는 메소드를 실행해야한다.

    아래에서 코드에서 이러한 요구 사항을 구현하는 방법에 대한 (거의) 완전한 예를 찾을 수 있습니다.

    업데이트 - 작업을 예약하는 코드

    먼저 SchedulingService 인터페이스를 정의합니다.

    public interface SchedulingService {
    
        startScheduler() throws SchedulerException;
    
        void standbyScheduler() throws SchedulerException;
    
        void shutdownScheduler() throws SchedulerException;
    
        void scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException;
    }
    

    그리고 관련 구현.

    @Service
    public class SchedulingServiceImpl implements SchedulingService {
    
        @Autowired
        private Scheduler scheduler;
    
        @Override
        public void startScheduler() throws SchedulerException {
            if (!scheduler.isStarted()) {
                scheduler.start();
            }
        }
    
        @Override
        public void standbyScheduler() throws SchedulerException {
            if (!scheduler.isInStandbyMode()) {
                scheduler.standby();
            }
        }
    
        @Override
        public void shutdownScheduler() throws SchedulerException {
            if (!scheduler.isShutdown()) {
                scheduler.shutdown();
            }
        }
    
        @Override
        public void scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException {
            scheduler.scheduleJob(jobDetail, trigger);
        }
    }
    

    그런 다음 AppointmentServiceImpl에 scheduleSendEmailJob ()을 호출하는 createAppointment () 메소드가 있습니다.

    @Service
    public class AppointmentServiceImpl implements AppointmentService {
    
        @Autowired
        private SchedulingService schedulingService;
    
        public void createAppointment(Appointment appointment) throws SchedulerException {
    
            // Save appointment to database
            // ...
    
            // Schedule send email job if appointment has been successfully saved
            scheduleSendEmailJob(appointment);
    
            return;
        }
    
        private void scheduleSendEmailJob(Appointment appointment) throws SchedulerException {
    
            JobDetail jobDetail = JobBuilder.newJob().ofType(SendEmailJob.class)
                .storeDurably()
                .withIdentity(UuidUtils.generateId(), "APPOINTMENT_NOTIFICATIONS")
                .withDescription("Send email notification for appointment")
                .build();
    
    
            jobDetail.getJobDataMap().put("appointmentId", appointment.getId());
    
            Date scheduleDate = appointment.computeDesiredScheduleDate();
            String cronExpression = convertDateToCronExpression(scheduleDate);
    
            CronTrigger trigger = TriggerBuilder.newTrigger().forJob(jobDetail)
                .withIdentity(UuidUtils.generateId(), "APPOINTMENT_NOTIFICATIONS")
                .withDescription("Trigger description")
                .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                .build();
    
            schedulingService.scheduleJob(jobDetail, trigger);
        }
    
        private String convertDateToCronExpression(Date date) {
    
            Calendar calendar = new GregorianCalendar();
    
            if (date == null) return null;
    
            calendar.setTime(date);
    
            int year = calendar.get(java.util.Calendar.YEAR);
            int month = calendar.get(java.util.Calendar.MONTH) + 1;
            int day = calendar.get(java.util.Calendar.DAY_OF_MONTH);
            int hour = calendar.get(java.util.Calendar.HOUR_OF_DAY);
            int minute = calendar.get(java.util.Calendar.MINUTE);
    
            return String.format("0 %d %d %d %d ? %d", minute, hour, day, month, year);
        }
    }
    

    SendEmailJob 클래스는 Job 인터페이스의 구현이며 관련 서비스를 사용하여 이메일을 전송합니다.

    업데이트 - 스케줄링 방법에서 실제 작업 실행으로 매개 변수를 전달하는 코드

    매개 변수를 전달할 때 jobDataMap이 사용됩니다. 예를 들면 :

    public class SendEmailJob implements Job {
    
        @Autowired
        private AppointmentService appointmentService;
    
        @Autowired
        private SendEmailService sendEmailService;
    
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    
            JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
    
            // Retrieving passed parameters
            Long appointmentId = (Long) jobDataMap.get("appointmentId");
    
            Appointment appointment = appointmentService.findById(appointmentId);
    
            // Send email
            sendEmailService.sendEmail(appointment);
        }
    }
    

    참고 : 예약 객체가 예약 메소드에서 실제 작업 실행으로 전달 될 수도 있습니다. 다음과 같이 전달할 수 있습니다.

    jobDetail.getJobDataMap().put("appointment", appointment);
    

    그리고 얻다:

    // Retrieving passed parameters
    Appointment appointment = (Appointment) jobDataMap.get("appointment");
    

    업데이트 - 구성 코드

    Bean 스케줄러는 Quartz 초기화를 담당하는 @Configuration 클래스에 정의된다.

    SchedulingConfiguration 클래스는 다음과 같이 정의됩니다.

    @Configuration
    public class SchedulingConfiguration {
    
        @Autowired
        private ApplicationContext applicationContext;
    
        @Bean
        public Scheduler scheduler() throws SchedulerException, IOException {
    
            StdSchedulerFactory factory = new StdSchedulerFactory();
            factory.initialize(new ClassPathResource("properties/quartz.properties").getInputStream());
    
            Scheduler scheduler = factory.getScheduler();
            scheduler.setJobFactory(springBeanJobFactory());
    
            return scheduler;
        }
    
        @Bean
        public SpringBeanJobFactory springBeanJobFactory() {
            AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
            jobFactory.setApplicationContext(applicationContext);
            return jobFactory;
        }
    
    }
    

    quartz.properties 파일은 resources / properties 폴더에 있습니다. 작업 지속성 데이터베이스는 Oracle 인스턴스입니다.

    # Configure Main Scheduler Properties
    org.quartz.scheduler.instanceName = AppScheduler
    org.quartz.scheduler.instanceId = AUTO
    
    # Configure ThreadPool
    org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
    org.quartz.threadPool.threadCount = 10
    org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
    
    # Configure JobStore
    org.quartz.jobStore.misfireThreshold = 60000
    org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
    org.quartz.jobStore.driverDelegateClass = 
    org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
    org.quartz.jobStore.tablePrefix = APP.QRTZ_
    org.quartz.jobStore.useProperties = false
    org.quartz.jobStore.dataSource = appDs
    org.quartz.jobStore.isClustered = true
    org.quartz.jobStore.clusterCheckinInterval = 20000
    
    # Configure Datasources
    org.quartz.dataSource.appDs.driver = oracle.jdbc.driver.OracleDriver
    org.quartz.dataSource.appDs.URL = jdbc:oracle:thin:@dbsrv:1521:appdb
    org.quartz.dataSource.appDs.user = db_user
    org.quartz.dataSource.appDs.password = db_pwd
    org.quartz.dataSource.appDs.maxConnections = 5
    org.quartz.dataSource.appDs.validationQuery = select 0 from dual
    

    마지막 단계는 다음과 같이 애플리케이션 컨텍스트 초기화에서 스케쥴러 메소드를 호출하는 것입니다 (SchedulingService에 추가 된 메소드를 참고하십시오).

    public class SchedulingContextListener implements ServletContextListener {
    
        private static final Logger logger = LogManager.getLogger(SchedulingContextListener.class);
    
        private SchedulingService schedulingService(ServletContextEvent sce) {
            WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
            return springContext.getBean(SchedulingService.class);
        }
    
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            try {
                this.schedulingService(sce).startScheduler();
            } catch (SchedulerException e) {
                logger.error("Error while Scheduler is being started", e);
            }
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            try {
                this.schedulingService(sce).shutdownScheduler();
            } catch (SchedulerException e) {
                logger.error("Error while Scheduler is being shutdown", e);
            }
        }
    }
    

    참고 : SchedulingContextListener는 스프링 초기화 또는 기존 스프링 MVC 구성을 사용하여 Spring 구성이 정의 된 방식에 따라 응용 프로그램 초기화시 servletContext에 등록되어야합니다.

    희망이 도움이됩니다.

  2. from https://stackoverflow.com/questions/46417393/full-spring-integration-with-quartz-to-implement-real-time-notification-e-mails by cc-by-sa and MIT license