From 39cd48b3d8393d8f7c1789651f86e603b504bc68 Mon Sep 17 00:00:00 2001 From: opensnail <598092184@qq.com> Date: Fri, 31 May 2024 11:27:19 +0800 Subject: [PATCH] =?UTF-8?q?feat(sj=5F1.0.0):=20=20=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=E4=BA=BA=E5=AF=BC=E5=85=A5=E5=AF=BC=E5=87=BA=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/NotifyRecipientController.java | 22 ++++ .../request/ExportNotifyRecipientVO.java | 20 +++ .../model/request/NotifyRecipientQueryVO.java | 2 + .../web/service/NotifyRecipientService.java | 7 ++ .../convert/NotifyRecipientConverter.java | 3 + .../web/service/handler/GroupHandler.java | 50 ++++++++ .../web/service/impl/JobServiceImpl.java | 115 ++++++++++-------- .../impl/NotifyRecipientServiceImpl.java | 85 +++++++++++-- .../service/impl/SceneConfigServiceImpl.java | 16 +-- .../web/service/impl/WorkflowServiceImpl.java | 29 ++--- 10 files changed, 261 insertions(+), 88 deletions(-) create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/request/ExportNotifyRecipientVO.java create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/handler/GroupHandler.java diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/NotifyRecipientController.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/NotifyRecipientController.java index 73c3a9d4..2aa264d1 100644 --- a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/NotifyRecipientController.java +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/NotifyRecipientController.java @@ -1,16 +1,25 @@ package com.aizuda.snailjob.server.web.controller; +import com.aizuda.snailjob.common.core.annotation.OriginalControllerReturnValue; import com.aizuda.snailjob.server.web.annotation.LoginRequired; +import com.aizuda.snailjob.server.web.annotation.RoleEnum; import com.aizuda.snailjob.server.web.model.base.PageResult; +import com.aizuda.snailjob.server.web.model.request.ExportNotifyRecipientVO; import com.aizuda.snailjob.server.web.model.request.NotifyRecipientQueryVO; import com.aizuda.snailjob.server.web.model.request.NotifyRecipientRequestVO; import com.aizuda.snailjob.server.web.model.response.CommonLabelValueResponseVO; import com.aizuda.snailjob.server.web.model.response.NotifyRecipientResponseVO; import com.aizuda.snailjob.server.web.service.NotifyRecipientService; +import com.aizuda.snailjob.server.web.util.ExportUtils; +import com.aizuda.snailjob.server.web.util.ImportUtils; import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; import java.util.List; import java.util.Set; @@ -57,4 +66,17 @@ public class NotifyRecipientController { public Boolean batchDeleteByIds(@RequestBody Set ids) { return notifyRecipientService.batchDeleteByIds(ids); } + + @PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @LoginRequired(role = RoleEnum.ADMIN) + public void importScene(@RequestPart("file") MultipartFile file) throws IOException { + notifyRecipientService.importNotifyRecipient(ImportUtils.parseList(file, NotifyRecipientRequestVO.class)); + } + + @PostMapping("/export") + @LoginRequired + @OriginalControllerReturnValue + public ResponseEntity exportGroup(@RequestBody ExportNotifyRecipientVO exportNotifyRecipientVO) { + return ExportUtils.doExport(notifyRecipientService.exportNotifyRecipient(exportNotifyRecipientVO)); + } } diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/request/ExportNotifyRecipientVO.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/request/ExportNotifyRecipientVO.java new file mode 100644 index 00000000..b9060d98 --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/request/ExportNotifyRecipientVO.java @@ -0,0 +1,20 @@ +package com.aizuda.snailjob.server.web.model.request; + +import lombok.Data; + +import java.util.Set; + +/** + * @author: opensnail + * @date : 2024-05-31 + * @since : sj_1.0.0 + */ +@Data +public class ExportNotifyRecipientVO { + + private Set notifyRecipientIds; + + private Integer notifyType; + + private String recipientName; +} diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/request/NotifyRecipientQueryVO.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/request/NotifyRecipientQueryVO.java index d159c06b..5fde4f4b 100644 --- a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/request/NotifyRecipientQueryVO.java +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/request/NotifyRecipientQueryVO.java @@ -2,12 +2,14 @@ package com.aizuda.snailjob.server.web.model.request; import com.aizuda.snailjob.server.web.model.base.BaseQueryVO; import lombok.Data; +import lombok.EqualsAndHashCode; /** * @author opensnail * @date 2024-04-17 21:26:22 * @since sj_1.0.0 */ +@EqualsAndHashCode(callSuper = true) @Data public class NotifyRecipientQueryVO extends BaseQueryVO { diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/NotifyRecipientService.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/NotifyRecipientService.java index fc45510d..89af2533 100644 --- a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/NotifyRecipientService.java +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/NotifyRecipientService.java @@ -1,10 +1,13 @@ package com.aizuda.snailjob.server.web.service; import com.aizuda.snailjob.server.web.model.base.PageResult; +import com.aizuda.snailjob.server.web.model.request.ExportNotifyRecipientVO; import com.aizuda.snailjob.server.web.model.request.NotifyRecipientQueryVO; import com.aizuda.snailjob.server.web.model.request.NotifyRecipientRequestVO; import com.aizuda.snailjob.server.web.model.response.CommonLabelValueResponseVO; import com.aizuda.snailjob.server.web.model.response.NotifyRecipientResponseVO; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; import java.util.List; import java.util.Set; @@ -25,4 +28,8 @@ public interface NotifyRecipientService { List getNotifyRecipientList(); Boolean batchDeleteByIds(Set ids); + + void importNotifyRecipient(@Valid @NotEmpty(message = "导入数据不能为空") List notifyRecipientRequestVOS); + + String exportNotifyRecipient(ExportNotifyRecipientVO exportNotifyRecipientVO); } diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/convert/NotifyRecipientConverter.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/convert/NotifyRecipientConverter.java index 1d7b4e00..4a0d9e97 100644 --- a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/convert/NotifyRecipientConverter.java +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/convert/NotifyRecipientConverter.java @@ -32,4 +32,7 @@ public interface NotifyRecipientConverter { @Mapping(target = "value", source = "id") }) CommonLabelValueResponseVO convert(NotifyRecipient notifyRecipient); + + List toNotifyRecipientRequestVOs(List notifyRecipients); + } diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/handler/GroupHandler.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/handler/GroupHandler.java new file mode 100644 index 00000000..d442d8fa --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/handler/GroupHandler.java @@ -0,0 +1,50 @@ +package com.aizuda.snailjob.server.web.service.handler; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import com.aizuda.snailjob.common.core.util.StreamUtils; +import com.aizuda.snailjob.server.common.exception.SnailJobServerException; +import com.aizuda.snailjob.template.datasource.access.AccessTemplate; +import com.aizuda.snailjob.template.datasource.persistence.po.GroupConfig; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.google.common.collect.Sets; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Set; + +/** + * @author: opensnail + * @date : 2024-05-31 + * @since : sj_1.0.0 + */ +@Component +@RequiredArgsConstructor +public class GroupHandler { + + private final AccessTemplate accessTemplate; + + /** + * 校验组是否存在 + * + * @param groupNameSet 待校验的组 + * @param namespaceId 空间 + */ + public void validateGroupExistence(Set groupNameSet, String namespaceId) { + Assert.notEmpty(groupNameSet, () -> new SnailJobServerException("组不能为空")); + List groupConfigs = accessTemplate.getGroupConfigAccess() + .list(new LambdaQueryWrapper() + .select(GroupConfig::getGroupName) + .eq(GroupConfig::getNamespaceId, namespaceId) + .in(GroupConfig::getGroupName, groupNameSet) + ); + + Set notExistedGroupNameSet = Sets.difference(groupNameSet, + StreamUtils.toSet(groupConfigs, GroupConfig::getGroupName)); + + Assert.isTrue(CollUtil.isEmpty(notExistedGroupNameSet), + () -> new SnailJobServerException("组:{}不存在", notExistedGroupNameSet)); + } + +} diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/JobServiceImpl.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/JobServiceImpl.java index 73c88982..d1482734 100644 --- a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/JobServiceImpl.java +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/JobServiceImpl.java @@ -27,6 +27,7 @@ import com.aizuda.snailjob.server.web.model.response.JobResponseVO; import com.aizuda.snailjob.server.web.service.JobService; import com.aizuda.snailjob.server.web.service.convert.JobConverter; import com.aizuda.snailjob.server.web.service.convert.JobResponseVOConverter; +import com.aizuda.snailjob.server.web.service.handler.GroupHandler; import com.aizuda.snailjob.server.web.util.UserSessionUtils; import com.aizuda.snailjob.template.datasource.access.AccessTemplate; import com.aizuda.snailjob.template.datasource.persistence.mapper.JobMapper; @@ -48,6 +49,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Set; /** * @author opensnail @@ -62,9 +64,9 @@ public class JobServiceImpl implements JobService { private final SystemProperties systemProperties; private final JobMapper jobMapper; - @Lazy private final JobPrepareHandler terminalJobPrepareHandler; private final AccessTemplate accessTemplate; + private final GroupHandler groupHandler; private static Long calculateNextTriggerAt(final JobRequestVO jobRequestVO, Long time) { if (Objects.equals(jobRequestVO.getTriggerType(), SystemConstants.WORKFLOW_TRIGGER_TYPE)) { @@ -84,14 +86,15 @@ public class JobServiceImpl implements JobService { PageDTO pageDTO = new PageDTO<>(queryVO.getPage(), queryVO.getSize()); UserSessionVO userSessionVO = UserSessionUtils.currentUserSession(); PageDTO selectPage = jobMapper.selectPage(pageDTO, - new LambdaQueryWrapper() - .eq(Job::getNamespaceId, userSessionVO.getNamespaceId()) - .in(userSessionVO.isUser(), Job::getGroupName, userSessionVO.getGroupNames()) - .eq(StrUtil.isNotBlank(queryVO.getGroupName()), Job::getGroupName, queryVO.getGroupName()) - .likeRight(StrUtil.isNotBlank(queryVO.getJobName()), Job::getJobName, StrUtil.trim(queryVO.getJobName())) - .eq(Objects.nonNull(queryVO.getJobStatus()), Job::getJobStatus, queryVO.getJobStatus()) - .eq(Job::getDeleted, StatusEnum.NO.getStatus()) - .orderByDesc(Job::getId)); + new LambdaQueryWrapper() + .eq(Job::getNamespaceId, userSessionVO.getNamespaceId()) + .in(userSessionVO.isUser(), Job::getGroupName, userSessionVO.getGroupNames()) + .eq(StrUtil.isNotBlank(queryVO.getGroupName()), Job::getGroupName, queryVO.getGroupName()) + .likeRight(StrUtil.isNotBlank(queryVO.getJobName()), Job::getJobName, + StrUtil.trim(queryVO.getJobName())) + .eq(Objects.nonNull(queryVO.getJobStatus()), Job::getJobStatus, queryVO.getJobStatus()) + .eq(Job::getDeleted, StatusEnum.NO.getStatus()) + .orderByDesc(Job::getId)); List jobResponseList = JobResponseVOConverter.INSTANCE.convertList(selectPage.getRecords()); @@ -114,16 +117,16 @@ public class JobServiceImpl implements JobService { UserSessionVO userSessionVO = UserSessionUtils.currentUserSession(); PageDTO selectPage = jobMapper.selectPage( - new PageDTO<>(1, 20), - new LambdaQueryWrapper() - .select(Job::getId, Job::getJobName) - .eq(Job::getNamespaceId, userSessionVO.getNamespaceId()) - .likeRight(StrUtil.isNotBlank(keywords), Job::getJobName, StrUtil.trim(keywords)) - .eq(StrUtil.isNotBlank(groupName), Job::getGroupName, groupName) - .eq(Objects.nonNull(jobId), Job::getId, jobId) - .eq(Job::getDeleted, StatusEnum.NO.getStatus()) - // SQLServer 分页必须 ORDER BY - .orderByAsc(Job::getId)); + new PageDTO<>(1, 20), + new LambdaQueryWrapper() + .select(Job::getId, Job::getJobName) + .eq(Job::getNamespaceId, userSessionVO.getNamespaceId()) + .likeRight(StrUtil.isNotBlank(keywords), Job::getJobName, StrUtil.trim(keywords)) + .eq(StrUtil.isNotBlank(groupName), Job::getGroupName, groupName) + .eq(Objects.nonNull(jobId), Job::getId, jobId) + .eq(Job::getDeleted, StatusEnum.NO.getStatus()) + // SQLServer 分页必须 ORDER BY + .orderByAsc(Job::getId)); return JobResponseVOConverter.INSTANCE.convertList(selectPage.getRecords()); } @@ -133,7 +136,7 @@ public class JobServiceImpl implements JobService { Job job = JobConverter.INSTANCE.convert(jobRequestVO); job.setResident(isResident(jobRequestVO)); job.setBucketIndex(HashUtil.bkdrHash(jobRequestVO.getGroupName() + jobRequestVO.getJobName()) - % systemProperties.getBucketTotal()); + % systemProperties.getBucketTotal()); job.setNextTriggerAt(calculateNextTriggerAt(jobRequestVO, DateUtils.toNowMilli())); job.setNamespaceId(UserSessionUtils.currentUserSession().getNamespaceId()); job.setId(null); @@ -157,18 +160,18 @@ public class JobServiceImpl implements JobService { job.setNextTriggerAt(0L); // 非常驻任务 > 非常驻任务 } else if (Objects.equals(job.getResident(), StatusEnum.NO.getStatus()) && Objects.equals( - updateJob.getResident(), - StatusEnum.NO.getStatus())) { + updateJob.getResident(), + StatusEnum.NO.getStatus())) { updateJob.setNextTriggerAt(calculateNextTriggerAt(jobRequestVO, DateUtils.toNowMilli())); } else if (Objects.equals(job.getResident(), StatusEnum.YES.getStatus()) && Objects.equals( - updateJob.getResident(), StatusEnum.NO.getStatus())) { + updateJob.getResident(), StatusEnum.NO.getStatus())) { // 常驻任务的触发时间 long time = Optional.ofNullable(ResidentTaskCache.get(jobRequestVO.getId())) - .orElse(DateUtils.toNowMilli()); + .orElse(DateUtils.toNowMilli()); updateJob.setNextTriggerAt(calculateNextTriggerAt(jobRequestVO, time)); // 老的是不是常驻任务 新的是常驻任务 需要使用当前时间计算下次触发时间 } else if (Objects.equals(job.getResident(), StatusEnum.NO.getStatus()) && Objects.equals( - updateJob.getResident(), StatusEnum.YES.getStatus())) { + updateJob.getResident(), StatusEnum.YES.getStatus())) { updateJob.setNextTriggerAt(DateUtils.toNowMilli()); } @@ -221,12 +224,13 @@ public class JobServiceImpl implements JobService { Assert.notNull(job, () -> new SnailJobServerException("job can not be null.")); long count = accessTemplate.getGroupConfigAccess().count(new LambdaQueryWrapper() - .eq(GroupConfig::getGroupName, job.getGroupName()) - .eq(GroupConfig::getNamespaceId, job.getNamespaceId()) - .eq(GroupConfig::getGroupStatus, StatusEnum.YES.getStatus()) + .eq(GroupConfig::getGroupName, job.getGroupName()) + .eq(GroupConfig::getNamespaceId, job.getNamespaceId()) + .eq(GroupConfig::getGroupStatus, StatusEnum.YES.getStatus()) ); - Assert.isTrue(count > 0, () -> new SnailJobServerException("组:[{}]已经关闭,不支持手动执行.", job.getGroupName())); + Assert.isTrue(count > 0, + () -> new SnailJobServerException("组:[{}]已经关闭,不支持手动执行.", job.getGroupName())); JobTaskPrepareDTO jobTaskPrepare = JobTaskConverter.INSTANCE.toJobTaskPrepare(job); // 设置now表示立即执行 jobTaskPrepare.setNextTriggerAt(DateUtils.toNowMilli()); @@ -241,12 +245,12 @@ public class JobServiceImpl implements JobService { public List getJobList(String groupName) { String namespaceId = UserSessionUtils.currentUserSession().getNamespaceId(); List jobs = jobMapper.selectList( - new LambdaQueryWrapper() - .select(Job::getId, Job::getJobName) - .eq(Job::getNamespaceId, namespaceId) - .eq(Job::getGroupName, groupName) - .eq(Job::getDeleted, StatusEnum.NO.getStatus()) - .orderByDesc(Job::getCreateDt)); + new LambdaQueryWrapper() + .select(Job::getId, Job::getJobName) + .eq(Job::getNamespaceId, namespaceId) + .eq(Job::getGroupName, groupName) + .eq(Job::getDeleted, StatusEnum.NO.getStatus()) + .orderByDesc(Job::getCreateDt)); List jobResponseList = JobResponseVOConverter.INSTANCE.convertList(jobs); return jobResponseList; } @@ -254,6 +258,10 @@ public class JobServiceImpl implements JobService { @Transactional(rollbackFor = Exception.class) @Override public void importJobs(List requestList) { + String namespaceId = UserSessionUtils.currentUserSession().getNamespaceId(); + groupHandler.validateGroupExistence( + StreamUtils.toSet(requestList, JobRequestVO::getJobName), namespaceId + ); requestList.forEach(this::saveJob); } @@ -263,23 +271,25 @@ public class JobServiceImpl implements JobService { List requestList = new ArrayList<>(); PartitionTaskUtils.process(startId -> { - List jobList = jobMapper.selectPage(new PageDTO<>(0, 100), - new LambdaQueryWrapper() - .eq(Job::getNamespaceId, namespaceId) - .eq(StrUtil.isNotBlank(exportJobVO.getGroupName()), Job::getGroupName, exportJobVO.getGroupName()) - .likeRight(StrUtil.isNotBlank(exportJobVO.getJobName()), Job::getJobName, StrUtil.trim(exportJobVO.getJobName())) - .eq(Objects.nonNull(exportJobVO.getJobStatus()), Job::getJobStatus, exportJobVO.getJobStatus()) - .in(CollUtil.isNotEmpty(exportJobVO.getJobIds()), Job::getId, exportJobVO.getJobIds()) - .eq(Job::getDeleted, StatusEnum.NO.getStatus()) - .gt(Job::getId, startId) - .orderByAsc(Job::getId) - ).getRecords(); - return StreamUtils.toList(jobList, JobPartitionTask::new); - }, - partitionTasks -> { - List jobPartitionTasks = (List) partitionTasks; - requestList.addAll(JobConverter.INSTANCE.convertList(StreamUtils.toList(jobPartitionTasks, JobPartitionTask::getJob))); - }, 0); + List jobList = jobMapper.selectPage(new PageDTO<>(0, 100), + new LambdaQueryWrapper() + .eq(Job::getNamespaceId, namespaceId) + .eq(StrUtil.isNotBlank(exportJobVO.getGroupName()), Job::getGroupName, exportJobVO.getGroupName()) + .likeRight(StrUtil.isNotBlank(exportJobVO.getJobName()), Job::getJobName, + StrUtil.trim(exportJobVO.getJobName())) + .eq(Objects.nonNull(exportJobVO.getJobStatus()), Job::getJobStatus, exportJobVO.getJobStatus()) + .in(CollUtil.isNotEmpty(exportJobVO.getJobIds()), Job::getId, exportJobVO.getJobIds()) + .eq(Job::getDeleted, StatusEnum.NO.getStatus()) + .gt(Job::getId, startId) + .orderByAsc(Job::getId) + ).getRecords(); + return StreamUtils.toList(jobList, JobPartitionTask::new); + }, + partitionTasks -> { + List jobPartitionTasks = (List) partitionTasks; + requestList.addAll( + JobConverter.INSTANCE.convertList(StreamUtils.toList(jobPartitionTasks, JobPartitionTask::getJob))); + }, 0); return JsonUtil.toJsonString(requestList); } @@ -287,6 +297,7 @@ public class JobServiceImpl implements JobService { @EqualsAndHashCode(callSuper = true) @Getter private static class JobPartitionTask extends PartitionTask { + // 这里就直接放GroupConfig为了后面若加字段不需要再这里在调整了 private final Job job; diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/NotifyRecipientServiceImpl.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/NotifyRecipientServiceImpl.java index e7043026..dd15b09a 100644 --- a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/NotifyRecipientServiceImpl.java +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/NotifyRecipientServiceImpl.java @@ -1,21 +1,34 @@ package com.aizuda.snailjob.server.web.service.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; +import com.aizuda.snailjob.common.core.util.JsonUtil; +import com.aizuda.snailjob.common.core.util.StreamUtils; +import com.aizuda.snailjob.server.common.dto.PartitionTask; +import com.aizuda.snailjob.server.common.util.PartitionTaskUtils; import com.aizuda.snailjob.server.web.model.base.PageResult; +import com.aizuda.snailjob.server.web.model.request.ExportNotifyRecipientVO; import com.aizuda.snailjob.server.web.model.request.NotifyRecipientQueryVO; import com.aizuda.snailjob.server.web.model.request.NotifyRecipientRequestVO; import com.aizuda.snailjob.server.web.model.response.CommonLabelValueResponseVO; import com.aizuda.snailjob.server.web.model.response.NotifyRecipientResponseVO; import com.aizuda.snailjob.server.web.service.NotifyRecipientService; import com.aizuda.snailjob.server.web.service.convert.NotifyRecipientConverter; +import com.aizuda.snailjob.server.web.service.handler.GroupHandler; import com.aizuda.snailjob.server.web.util.UserSessionUtils; import com.aizuda.snailjob.template.datasource.persistence.mapper.NotifyRecipientMapper; import com.aizuda.snailjob.template.datasource.persistence.po.NotifyRecipient; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO; +import lombok.EqualsAndHashCode; +import lombok.Getter; import lombok.RequiredArgsConstructor; +import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Set; @@ -27,21 +40,26 @@ import java.util.Set; */ @Service @RequiredArgsConstructor +@Validated public class NotifyRecipientServiceImpl implements NotifyRecipientService { private final NotifyRecipientMapper notifyRecipientMapper; + private final GroupHandler groupHandler; @Override public PageResult> getNotifyRecipientPageList(NotifyRecipientQueryVO queryVO) { + String namespaceId = UserSessionUtils.currentUserSession().getNamespaceId(); PageDTO pageDTO = new PageDTO<>(queryVO.getPage(), queryVO.getSize()); PageDTO notifyRecipientPageDTO = notifyRecipientMapper.selectPage(pageDTO, - new LambdaQueryWrapper() - .likeRight(StrUtil.isNotBlank(queryVO.getRecipientName()), NotifyRecipient::getRecipientName, queryVO.getRecipientName()) - .likeRight(Objects.nonNull(queryVO.getNotifyType()), NotifyRecipient::getNotifyType, queryVO.getNotifyType()) - .orderByDesc(NotifyRecipient::getCreateDt)); + new LambdaQueryWrapper() + .eq(NotifyRecipient::getNamespaceId, namespaceId) + .eq(Objects.nonNull(queryVO.getNotifyType()), NotifyRecipient::getNotifyType, queryVO.getNotifyType()) + .likeRight(StrUtil.isNotBlank(queryVO.getRecipientName()), NotifyRecipient::getRecipientName, + queryVO.getRecipientName()) + .orderByDesc(NotifyRecipient::getCreateDt)); return new PageResult<>(pageDTO, - NotifyRecipientConverter.INSTANCE.convertList(notifyRecipientPageDTO.getRecords())); + NotifyRecipientConverter.INSTANCE.convertList(notifyRecipientPageDTO.getRecords())); } @Override @@ -49,6 +67,7 @@ public class NotifyRecipientServiceImpl implements NotifyRecipientService { String namespaceId = UserSessionUtils.currentUserSession().getNamespaceId(); NotifyRecipient notifyRecipient = NotifyRecipientConverter.INSTANCE.convert(requestVO); notifyRecipient.setNamespaceId(namespaceId); + notifyRecipient.setId(null); return 1 == notifyRecipientMapper.insert(notifyRecipient); } @@ -62,9 +81,12 @@ public class NotifyRecipientServiceImpl implements NotifyRecipientService { @Override public List getNotifyRecipientList() { + String namespaceId = UserSessionUtils.currentUserSession().getNamespaceId(); List notifyRecipients = notifyRecipientMapper.selectList( - new LambdaQueryWrapper() - .select(NotifyRecipient::getRecipientName, NotifyRecipient::getId)); + new LambdaQueryWrapper() + .select(NotifyRecipient::getRecipientName, NotifyRecipient::getId) + .eq(NotifyRecipient::getNamespaceId, namespaceId) + ); return NotifyRecipientConverter.INSTANCE.convertListToCommonLabelValueList(notifyRecipients); } @@ -72,4 +94,53 @@ public class NotifyRecipientServiceImpl implements NotifyRecipientService { public Boolean batchDeleteByIds(final Set ids) { return ids.size() == notifyRecipientMapper.deleteBatchIds(ids); } + + @Override + @Transactional + public void importNotifyRecipient(final List notifyRecipientRequestVOS) { + for (final NotifyRecipientRequestVO notifyRecipientRequestVO : notifyRecipientRequestVOS) { + this.saveNotifyRecipient(notifyRecipientRequestVO); + } + } + + @Override + public String exportNotifyRecipient(final ExportNotifyRecipientVO exportVO) { + + List requestList = new ArrayList<>(); + String namespaceId = UserSessionUtils.currentUserSession().getNamespaceId(); + PartitionTaskUtils.process(startId -> { + List recipients = notifyRecipientMapper.selectPage(new PageDTO<>(0, 100), + new LambdaQueryWrapper() + .eq(NotifyRecipient::getNamespaceId, namespaceId) + .eq(Objects.nonNull(exportVO.getNotifyType()), NotifyRecipient::getNotifyType, + exportVO.getNotifyType()) + .likeRight(StrUtil.isNotBlank(exportVO.getRecipientName()), NotifyRecipient::getRecipientName, + exportVO.getRecipientName()) + .ge(NotifyRecipient::getId, startId) + .in(CollUtil.isNotEmpty(exportVO.getNotifyRecipientIds()), NotifyRecipient::getId, + exportVO.getNotifyRecipientIds()) + .orderByAsc(NotifyRecipient::getId)).getRecords(); + return StreamUtils.toList(recipients, NotifyRecipientPartitionTask::new); + }, partitionTasks -> { + List partitionTaskList = (List) partitionTasks; + List notifyRecipientRequestVOs = NotifyRecipientConverter.INSTANCE.toNotifyRecipientRequestVOs( + StreamUtils.toList(partitionTaskList, NotifyRecipientPartitionTask::getRecipient)); + requestList.addAll(notifyRecipientRequestVOs); + }, 0); + + return JsonUtil.toJsonString(requestList); + } + + @EqualsAndHashCode(callSuper = true) + @Getter + private static class NotifyRecipientPartitionTask extends PartitionTask { + + // 这里就直接放NotifyRecipient为了后面若加字段不需要再这里在调整了 + private final NotifyRecipient recipient; + + public NotifyRecipientPartitionTask(@NotNull NotifyRecipient recipient) { + this.recipient = recipient; + setId(recipient.getId()); + } + } } diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/SceneConfigServiceImpl.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/SceneConfigServiceImpl.java index c1e9797e..62bb48bc 100644 --- a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/SceneConfigServiceImpl.java +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/SceneConfigServiceImpl.java @@ -19,6 +19,7 @@ import com.aizuda.snailjob.server.web.model.response.SceneConfigResponseVO; import com.aizuda.snailjob.server.web.service.SceneConfigService; import com.aizuda.snailjob.server.web.service.convert.SceneConfigConverter; import com.aizuda.snailjob.server.web.service.convert.SceneConfigResponseVOConverter; +import com.aizuda.snailjob.server.web.service.handler.GroupHandler; import com.aizuda.snailjob.server.web.service.handler.SyncConfigHandler; import com.aizuda.snailjob.server.web.util.UserSessionUtils; import com.aizuda.snailjob.template.datasource.access.AccessTemplate; @@ -53,7 +54,7 @@ import java.util.*; public class SceneConfigServiceImpl implements SceneConfigService { private final AccessTemplate accessTemplate; - private final NamespaceMapper namespaceMapper; + private final GroupHandler groupHandler; private static void checkExecuteInterval(SceneConfigRequestVO requestVO) { if (Lists.newArrayList(WaitStrategies.WaitStrategyEnum.FIXED.getType(), @@ -231,18 +232,7 @@ public class SceneConfigServiceImpl implements SceneConfigService { sceneNameSet.add(request.getSceneName()); } - List groupConfigs = accessTemplate.getGroupConfigAccess() - .list(new LambdaQueryWrapper() - .select(GroupConfig::getGroupName) - .eq(GroupConfig::getNamespaceId, namespaceId) - .in(GroupConfig::getGroupName, groupNameSet) - ); - - SetView notExistedGroupNameSet = Sets.difference(groupNameSet, - StreamUtils.toSet(groupConfigs, GroupConfig::getGroupName)); - - Assert.isTrue(CollUtil.isEmpty(notExistedGroupNameSet), - () -> new SnailJobServerException("导入失败. 原因: 组{}不存在", notExistedGroupNameSet)); + groupHandler.validateGroupExistence(groupNameSet, namespaceId); ConfigAccess sceneConfigAccess = accessTemplate.getSceneConfigAccess(); List sceneConfigs = sceneConfigAccess.list( diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/WorkflowServiceImpl.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/WorkflowServiceImpl.java index be9d09a9..d9eda892 100644 --- a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/WorkflowServiceImpl.java +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/WorkflowServiceImpl.java @@ -39,6 +39,7 @@ import com.aizuda.snailjob.server.web.model.response.WorkflowDetailResponseVO; import com.aizuda.snailjob.server.web.model.response.WorkflowResponseVO; import com.aizuda.snailjob.server.web.service.WorkflowService; import com.aizuda.snailjob.server.web.service.convert.WorkflowConverter; +import com.aizuda.snailjob.server.web.service.handler.GroupHandler; import com.aizuda.snailjob.server.web.service.handler.WorkflowHandler; import com.aizuda.snailjob.server.web.util.UserSessionUtils; import com.aizuda.snailjob.template.datasource.access.AccessTemplate; @@ -61,6 +62,7 @@ import org.jetbrains.annotations.NotNull; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; import java.util.*; import java.util.concurrent.LinkedBlockingDeque; @@ -74,16 +76,17 @@ import java.util.stream.Collectors; @Service @Slf4j @RequiredArgsConstructor +@Validated public class WorkflowServiceImpl implements WorkflowService { private final WorkflowMapper workflowMapper; private final WorkflowNodeMapper workflowNodeMapper; private final SystemProperties systemProperties; private final WorkflowHandler workflowHandler; - @Lazy private final WorkflowPrePareHandler terminalWorkflowPrepareHandler; private final JobMapper jobMapper; private final AccessTemplate accessTemplate; + private final GroupHandler groupHandler; private static Long calculateNextTriggerAt(final WorkflowRequestVO workflowRequestVO, Long time) { checkExecuteInterval(workflowRequestVO); @@ -315,6 +318,7 @@ public class WorkflowServiceImpl implements WorkflowService { @Override @Transactional(rollbackFor = Exception.class) public void importWorkflowTask(List requests) { + batchSaveWorkflowTask(requests, UserSessionUtils.currentUserSession().getNamespaceId()); } @@ -328,8 +332,10 @@ public class WorkflowServiceImpl implements WorkflowService { .eq(Workflow::getNamespaceId, UserSessionUtils.currentUserSession().getNamespaceId()) .eq(Workflow::getDeleted, StatusEnum.NO.getStatus()) .eq(StrUtil.isNotBlank(exportVO.getGroupName()), Workflow::getGroupName, exportVO.getGroupName()) - .eq(Objects.nonNull(exportVO.getWorkflowStatus()), Workflow::getWorkflowStatus, exportVO.getWorkflowStatus()) - .likeRight(StrUtil.isNotBlank(exportVO.getWorkflowName()), Workflow::getWorkflowName, exportVO.getWorkflowName()) + .eq(Objects.nonNull(exportVO.getWorkflowStatus()), Workflow::getWorkflowStatus, + exportVO.getWorkflowStatus()) + .likeRight(StrUtil.isNotBlank(exportVO.getWorkflowName()), Workflow::getWorkflowName, + exportVO.getWorkflowName()) .in(CollUtil.isNotEmpty(exportVO.getWorkflowIds()), Workflow::getId, exportVO.getWorkflowIds()) .ge(Workflow::getId, startId) .orderByAsc(Workflow::getId) @@ -348,19 +354,8 @@ public class WorkflowServiceImpl implements WorkflowService { private void batchSaveWorkflowTask(final List workflowRequestVOList, final String namespaceId) { - Set groupNameSet =StreamUtils.toSet(workflowRequestVOList, WorkflowRequestVO::getGroupName); - List groupConfigs = accessTemplate.getGroupConfigAccess() - .list(new LambdaQueryWrapper() - .select(GroupConfig::getGroupName) - .eq(GroupConfig::getNamespaceId, namespaceId) - .in(GroupConfig::getGroupName, groupNameSet) - ); - - Sets.SetView notExistedGroupNameSet = Sets.difference(groupNameSet, - StreamUtils.toSet(groupConfigs, GroupConfig::getGroupName)); - - Assert.isTrue(CollUtil.isEmpty(notExistedGroupNameSet), - () -> new SnailJobServerException("导入失败. 原因: 组{}不存在", notExistedGroupNameSet)); + Set groupNameSet = StreamUtils.toSet(workflowRequestVOList, WorkflowRequestVO::getGroupName); + groupHandler.validateGroupExistence(groupNameSet, namespaceId); for (final WorkflowRequestVO workflowRequestVO : workflowRequestVOList) { checkExecuteInterval(workflowRequestVO); @@ -412,7 +407,9 @@ public class WorkflowServiceImpl implements WorkflowService { @EqualsAndHashCode(callSuper = true) @Getter private static class WorkflowPartitionTask extends PartitionTask { + private final WorkflowDetailResponseVO responseVO; + public WorkflowPartitionTask(@NotNull WorkflowDetailResponseVO responseVO) { this.responseVO = responseVO; setId(responseVO.getId());