feat(sj_1.0.0): 优化重试场景和组导出导入

This commit is contained in:
opensnail 2024-05-29 10:39:03 +08:00
parent c988269333
commit 99cf046138
6 changed files with 21 additions and 112 deletions

View File

@ -1,12 +1,7 @@
package com.aizuda.snailjob.server.web.controller; package com.aizuda.snailjob.server.web.controller;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import com.aizuda.snailjob.common.core.annotation.OriginalControllerReturnValue; import com.aizuda.snailjob.common.core.annotation.OriginalControllerReturnValue;
import com.aizuda.snailjob.common.core.exception.SnailJobCommonException; import com.aizuda.snailjob.common.core.exception.SnailJobCommonException;
import com.aizuda.snailjob.common.core.util.JsonUtil;
import com.aizuda.snailjob.server.common.exception.SnailJobServerException;
import com.aizuda.snailjob.server.common.util.DateUtils;
import com.aizuda.snailjob.server.web.annotation.LoginRequired; import com.aizuda.snailjob.server.web.annotation.LoginRequired;
import com.aizuda.snailjob.server.web.annotation.RoleEnum; import com.aizuda.snailjob.server.web.annotation.RoleEnum;
import com.aizuda.snailjob.server.web.model.base.PageResult; import com.aizuda.snailjob.server.web.model.base.PageResult;
@ -14,13 +9,9 @@ import com.aizuda.snailjob.server.web.model.request.GroupConfigQueryVO;
import com.aizuda.snailjob.server.web.model.request.GroupConfigRequestVO; import com.aizuda.snailjob.server.web.model.request.GroupConfigRequestVO;
import com.aizuda.snailjob.server.web.model.response.GroupConfigResponseVO; import com.aizuda.snailjob.server.web.model.response.GroupConfigResponseVO;
import com.aizuda.snailjob.server.web.service.GroupConfigService; import com.aizuda.snailjob.server.web.service.GroupConfigService;
import com.fasterxml.jackson.databind.JsonNode; import com.aizuda.snailjob.server.web.util.ExportUtils;
import jakarta.validation.ConstraintViolation; import com.aizuda.snailjob.server.web.util.ImportUtils;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -28,7 +19,6 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -42,7 +32,6 @@ import java.util.Set;
@RequestMapping("/group") @RequestMapping("/group")
@RequiredArgsConstructor @RequiredArgsConstructor
public class GroupConfigController { public class GroupConfigController {
private static final List<String> FILE_EXTENSIONS = List.of("json");
private final GroupConfigService groupConfigService; private final GroupConfigService groupConfigService;
@LoginRequired(role = RoleEnum.ADMIN) @LoginRequired(role = RoleEnum.ADMIN)
@ -105,51 +94,16 @@ public class GroupConfigController {
@LoginRequired(role = RoleEnum.ADMIN) @LoginRequired(role = RoleEnum.ADMIN)
public void importScene(@RequestPart("file") MultipartFile file) throws IOException { public void importScene(@RequestPart("file") MultipartFile file) throws IOException {
if (file.isEmpty()) { if (file.isEmpty()) {
throw new SnailJobCommonException("Please select a file to upload"); throw new SnailJobCommonException("请选择一个文件上传");
} }
// 保存文件到服务器 groupConfigService.importGroup(ImportUtils.parseList(file, GroupConfigRequestVO.class));
String suffix = FileUtil.getSuffix(file.getOriginalFilename());
if (!FILE_EXTENSIONS.contains(suffix)) {
throw new SnailJobCommonException("文件类型错误");
}
JsonNode node = JsonUtil.toJson(file.getBytes());
List<GroupConfigRequestVO> requestList = JsonUtil.parseList(JsonUtil.toJsonString(node),
GroupConfigRequestVO.class);
Assert.notEmpty(requestList, () -> new SnailJobServerException("导入数据不能为空"));
// 校验参数是否合法
for (final GroupConfigRequestVO groupConfigRequestVO : requestList) {
ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
Validator validator = vf.getValidator();
Set<ConstraintViolation<GroupConfigRequestVO>> set = validator.validate(groupConfigRequestVO);
for (final ConstraintViolation<GroupConfigRequestVO> violation : set) {
throw new SnailJobCommonException(violation.getMessage());
}
}
groupConfigService.importGroup(requestList);
} }
@PostMapping("/export") @PostMapping("/export")
@LoginRequired(role = RoleEnum.ADMIN) @LoginRequired
@OriginalControllerReturnValue @OriginalControllerReturnValue
public ResponseEntity<String> exportGroup(@RequestBody Set<Long> groupIds) { public ResponseEntity<String> exportGroup(@RequestBody Set<Long> groupIds) {
return ExportUtils.doExport(groupConfigService.exportGroup(groupIds));
String configs = groupConfigService.exportGroup(groupIds);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 设置下载时的文件名称
String fileName = String.format("group-config-%s.json", DateUtils.toNowFormat(DateUtils.PURE_DATETIME_MS_PATTERN));
String disposition = "attachment; filename=" +
new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
headers.add(HttpHeaders.CONTENT_DISPOSITION, disposition);
return ResponseEntity.ok()
.headers(headers)
.body(configs);
} }
} }

View File

@ -1,26 +1,16 @@
package com.aizuda.snailjob.server.web.controller; package com.aizuda.snailjob.server.web.controller;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import com.aizuda.snailjob.common.core.annotation.OriginalControllerReturnValue; import com.aizuda.snailjob.common.core.annotation.OriginalControllerReturnValue;
import com.aizuda.snailjob.common.core.exception.SnailJobCommonException; import com.aizuda.snailjob.common.core.exception.SnailJobCommonException;
import com.aizuda.snailjob.common.core.util.JsonUtil;
import com.aizuda.snailjob.server.common.exception.SnailJobServerException;
import com.aizuda.snailjob.server.common.util.DateUtils;
import com.aizuda.snailjob.server.web.annotation.LoginRequired; import com.aizuda.snailjob.server.web.annotation.LoginRequired;
import com.aizuda.snailjob.server.web.model.base.PageResult; import com.aizuda.snailjob.server.web.model.base.PageResult;
import com.aizuda.snailjob.server.web.model.request.SceneConfigQueryVO; import com.aizuda.snailjob.server.web.model.request.SceneConfigQueryVO;
import com.aizuda.snailjob.server.web.model.request.SceneConfigRequestVO; import com.aizuda.snailjob.server.web.model.request.SceneConfigRequestVO;
import com.aizuda.snailjob.server.web.model.response.SceneConfigResponseVO; import com.aizuda.snailjob.server.web.model.response.SceneConfigResponseVO;
import com.aizuda.snailjob.server.web.service.SceneConfigService; import com.aizuda.snailjob.server.web.service.SceneConfigService;
import com.fasterxml.jackson.databind.JsonNode; import com.aizuda.snailjob.server.web.util.ExportUtils;
import jakarta.validation.ConstraintViolation; import com.aizuda.snailjob.server.web.util.ImportUtils;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -28,7 +18,6 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -42,8 +31,6 @@ import java.util.Set;
@RequestMapping("/scene-config") @RequestMapping("/scene-config")
@RequiredArgsConstructor @RequiredArgsConstructor
public class SceneConfigController { public class SceneConfigController {
private static final List<String> FILE_EXTENSIONS = List.of("json");
private final SceneConfigService sceneConfigService; private final SceneConfigService sceneConfigService;
@LoginRequired @LoginRequired
@ -86,52 +73,19 @@ public class SceneConfigController {
@PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void importScene(@RequestPart("file") MultipartFile file) throws IOException { public void importScene(@RequestPart("file") MultipartFile file) throws IOException {
if (file.isEmpty()) { if (file.isEmpty()) {
throw new SnailJobCommonException("Please select a file to upload"); throw new SnailJobCommonException("请选择一个文件上传");
}
// 保存文件到服务器
String suffix = FileUtil.getSuffix(file.getOriginalFilename());
if (!FILE_EXTENSIONS.contains(suffix)) {
throw new SnailJobCommonException("文件类型错误");
}
JsonNode node = JsonUtil.toJson(file.getBytes());
List<SceneConfigRequestVO> requestList = JsonUtil.parseList(JsonUtil.toJsonString(node),
SceneConfigRequestVO.class);
Assert.notEmpty(requestList, () -> new SnailJobServerException("导入数据不能为空"));
// 校验参数是否合法
for (final SceneConfigRequestVO sceneConfigRequestVO : requestList) {
ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
Validator validator = vf.getValidator();
Set<ConstraintViolation<SceneConfigRequestVO>> set = validator.validate(sceneConfigRequestVO);
for (final ConstraintViolation<SceneConfigRequestVO> violation : set) {
throw new SnailJobCommonException(violation.getMessage());
}
} }
// 写入数据 // 写入数据
sceneConfigService.importSceneConfig(requestList); sceneConfigService.importSceneConfig(ImportUtils.parseList(file, SceneConfigRequestVO.class));
} }
@LoginRequired @LoginRequired
@PostMapping("/export") @PostMapping("/export")
@OriginalControllerReturnValue @OriginalControllerReturnValue
public ResponseEntity<String> export(@RequestBody Set<Long> sceneIds) { public ResponseEntity<String> export(@RequestBody Set<Long> sceneIds) {
String configs = sceneConfigService.exportSceneConfig(sceneIds); return ExportUtils.doExport(sceneConfigService.exportSceneConfig(sceneIds));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 设置下载时的文件名称
String fileName = String.format("retry-scene-%s.json", DateUtils.toNowFormat(DateUtils.PURE_DATETIME_MS_PATTERN));
String disposition = "attachment; filename=" +
new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
headers.add(HttpHeaders.CONTENT_DISPOSITION, disposition);
return ResponseEntity.ok()
.headers(headers)
.body(configs);
} }
} }

View File

@ -4,6 +4,8 @@ import com.aizuda.snailjob.server.web.model.base.PageResult;
import com.aizuda.snailjob.server.web.model.request.GroupConfigQueryVO; import com.aizuda.snailjob.server.web.model.request.GroupConfigQueryVO;
import com.aizuda.snailjob.server.web.model.request.GroupConfigRequestVO; import com.aizuda.snailjob.server.web.model.request.GroupConfigRequestVO;
import com.aizuda.snailjob.server.web.model.response.GroupConfigResponseVO; import com.aizuda.snailjob.server.web.model.response.GroupConfigResponseVO;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -32,7 +34,7 @@ public interface GroupConfigService {
List<Integer> getTablePartitionList(); List<Integer> getTablePartitionList();
void importGroup(List<GroupConfigRequestVO> requestVOS); void importGroup(@Valid @NotEmpty(message = "导入数据不能为空") List<GroupConfigRequestVO> requestVOS);
String exportGroup(Set<Long> groupIds); String exportGroup(Set<Long> groupIds);
} }

View File

@ -4,6 +4,8 @@ import com.aizuda.snailjob.server.web.model.base.PageResult;
import com.aizuda.snailjob.server.web.model.request.SceneConfigQueryVO; import com.aizuda.snailjob.server.web.model.request.SceneConfigQueryVO;
import com.aizuda.snailjob.server.web.model.request.SceneConfigRequestVO; import com.aizuda.snailjob.server.web.model.request.SceneConfigRequestVO;
import com.aizuda.snailjob.server.web.model.response.SceneConfigResponseVO; import com.aizuda.snailjob.server.web.model.response.SceneConfigResponseVO;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -26,7 +28,7 @@ public interface SceneConfigService {
boolean updateStatus(Long id, final Integer status); boolean updateStatus(Long id, final Integer status);
void importSceneConfig(List<SceneConfigRequestVO> requests); void importSceneConfig(@Valid @NotEmpty(message = "导入数据不能为空") List<SceneConfigRequestVO> requests);
String exportSceneConfig(Set<Long> sceneIds); String exportSceneConfig(Set<Long> sceneIds);

View File

@ -31,14 +31,10 @@ import com.aizuda.snailjob.template.datasource.persistence.mapper.SequenceAllocM
import com.aizuda.snailjob.template.datasource.persistence.mapper.ServerNodeMapper; import com.aizuda.snailjob.template.datasource.persistence.mapper.ServerNodeMapper;
import com.aizuda.snailjob.template.datasource.persistence.po.*; import com.aizuda.snailjob.template.datasource.persistence.po.*;
import com.aizuda.snailjob.template.datasource.utils.DbUtils; import com.aizuda.snailjob.template.datasource.utils.DbUtils;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO; import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -47,6 +43,7 @@ import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.sql.Connection; import java.sql.Connection;
@ -55,8 +52,6 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.function.Consumer;
import java.util.function.LongFunction;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -68,6 +63,7 @@ import java.util.stream.Collectors;
*/ */
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@Validated
public class GroupConfigServiceImpl implements GroupConfigService { public class GroupConfigServiceImpl implements GroupConfigService {
private final ServerNodeMapper serverNodeMapper; private final ServerNodeMapper serverNodeMapper;

View File

@ -30,9 +30,9 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView; import com.google.common.collect.Sets.SetView;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.checkerframework.checker.units.qual.C;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@ -45,6 +45,7 @@ import java.util.Set;
*/ */
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@Validated
public class SceneConfigServiceImpl implements SceneConfigService { public class SceneConfigServiceImpl implements SceneConfigService {
private final AccessTemplate accessTemplate; private final AccessTemplate accessTemplate;