首页 > 解决方案 > 使用 Quartz 和 Spring boot 安排任务

问题描述

我想每天使用 Spring boot 发送电子邮件,用户指定发送时间,我使用石英来安排我的工作。电子邮件的收件人有(id,emailAddress,deadline) 电子邮件将发送给有deadline = Today + X..(用户指定X)的人。例如:用户指定 X 是数字 1,所以我们对明天有截止日期的人感兴趣。

第 1 天:应用程序向截止日期 = 今天 +1 的人发送电子邮件。第 2 天:我希望应用程序在第 2 天将电子邮件发送给新的收件人,但是使用下面的代码,电子邮件会发送给收到它的人Day1,这不是我需要的。

@PostMapping("/scheduleEmailPeriodic")
    public ResponseEntity<ScheduleEmailResponse> SendScheduleEmailPeriodic(
            @Valid @RequestBody PeriodicNotification scheduleEmailRequest) throws Exception {
        ens.schedulePeriodicNotification(scheduleEmailRequest);
        LocalDate localDateTime = LocalDate.now();
        LocalTime localTime = LocalTime.parse(scheduleEmailRequest.getSendingTime());

        

        try {
            ZonedDateTime dateTime = ZonedDateTime.of(localDateTime, localTime,ZoneId.of("Africa/Casablanca"));
            if (dateTime.isBefore(ZonedDateTime.now())) {
                ScheduleEmailResponse scheduleEmailResponse = new ScheduleEmailResponse(false,
                        "dateTime must be after current time");
                return ResponseEntity.badRequest().body(scheduleEmailResponse);
            }

            JobDetail jobDetail = buildPeriodicJobDetail(scheduleEmailRequest);
            Trigger trigger = buildJobTriggerPeriodic(jobDetail, dateTime);
            scheduler.scheduleJob(jobDetail, trigger);

            ScheduleEmailResponse scheduleEmailResponse = new ScheduleEmailResponse(true, jobDetail.getKey().getName(),
                    jobDetail.getKey().getGroup(), "Email Scheduled Successfully!");
            return ResponseEntity.ok(scheduleEmailResponse);
        } catch (SchedulerException ex) {
            logger.error("Error scheduling email", ex);

            ScheduleEmailResponse scheduleEmailResponse = new ScheduleEmailResponse(false,
                    "Error scheduling email. Please try later!");
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(scheduleEmailResponse);
        }
    }

private JobDetail buildPeriodicJobDetail(PeriodicNotification scheduleEmailRequest) {
        JobDataMap jobDataMap = new JobDataMap();
        List<String> recipients = fileRepo.findWantedEmails(scheduleEmailRequest.getDaysNum());

        if(recipients.isEmpty()) {
            throw new RuntimeException("Aucun destinataire trouvé");
        }
        String[] to = recipients.stream().toArray(String[]::new);

        jobDataMap.put("recipients", to);
        jobDataMap.put("subject", scheduleEmailRequest.getSubject());
        jobDataMap.put("body", scheduleEmailRequest.getMessage());

        return JobBuilder.newJob(EmailJob.class).withIdentity(UUID.randomUUID().toString(), "email-jobs")
                .withDescription("Send Email Job").usingJobData(jobDataMap).storeDurably().build();
    }

    private Trigger buildJobTriggerPeriodic(JobDetail jobDetail, ZonedDateTime startAt) {
        return TriggerBuilder.newTrigger().forJob(jobDetail)
                .withIdentity(jobDetail.getKey().getName(), "email-triggers")
                .withDescription("Send Periodic Email Trigger")
                .withSchedule(SimpleScheduleBuilder
                .repeatHourlyForever(24))
                .startAt(Date.from(startAt.toInstant()))
                .build();
    }

这是电子邮件工作:

@Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        logger.info("Executing Job with key {}", context.getJobDetail().getKey());
        JobDataMap jobDataMap = context.getMergedJobDataMap();
        String subject = jobDataMap.getString("subject");
        String body = jobDataMap.getString("body");
        String[] recipients = (String[])jobDataMap.get("recipients");
        sendMail("smsender4@gmail.com", recipients, subject, body);
        
    }
    
     private void sendMail(String fromEmail, String[] toEmail, String subject, String body) {
            try {
                logger.info("Sending Email to {}", Arrays.toString(toEmail));
                MimeMessage message = mailSender.createMimeMessage();

                MimeMessageHelper messageHelper = new MimeMessageHelper(message, StandardCharsets.UTF_8.toString());
                messageHelper.setSubject(subject);
                messageHelper.setText(body, true);
                messageHelper.setFrom(fromEmail);
                messageHelper.setTo(toEmail);

                mailSender.send(message);
            } catch (MessagingException ex) {
                logger.error("Failed to send email to {}", Arrays.toString(toEmail));
            }
        }

}

我真的需要帮助,我每天都需要获得新的收件人,而不是将电子邮件发送给相同的收件人。

标签: spring-boottriggerscronquartz-schedulerjob-scheduling

解决方案


您正在根据日期发送电子邮件 - 但您不会跟踪为特定用户发送电子邮件的时间。因此,如果您今天向 user1 发送一封电子邮件 - 那么 user1 仍然处于第二天的状态。您需要添加一个标志(或其他一些逻辑),说明已为此用户发送了电子邮件


推荐阅读