1
0

feat(web): 使用统一的超类和子图查询来优化查询性能

This commit is contained in:
2024-11-21 19:17:14 +08:00
parent ccbefb9bdf
commit c51228bf42
15 changed files with 300 additions and 80 deletions

View File

@@ -1,4 +1,4 @@
package com.eshore.gringotts.web.domain.entity; package com.eshore.gringotts.web.domain.base.entity;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import javax.persistence.EntityListeners; import javax.persistence.EntityListeners;

View File

@@ -1,22 +1,13 @@
package com.eshore.gringotts.web.domain.entity; package com.eshore.gringotts.web.domain.base.entity;
import com.eshore.gringotts.web.domain.user.entity.User;
import java.time.LocalDateTime;
import javax.persistence.ConstraintMode;
import javax.persistence.EntityListeners; import javax.persistence.EntityListeners;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import javax.persistence.OneToOne;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerator;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener; import org.springframework.data.jpa.domain.support.AuditingEntityListener;
/** /**

View File

@@ -1,4 +1,4 @@
package com.eshore.gringotts.web.domain.entity; package com.eshore.gringotts.web.domain.base.entity;
import com.eshore.gringotts.web.domain.user.entity.User; import com.eshore.gringotts.web.domain.user.entity.User;
import java.time.LocalDateTime; import java.time.LocalDateTime;

View File

@@ -0,0 +1,25 @@
package com.eshore.gringotts.web.domain.base.service;
import cn.hutool.core.util.ObjectUtil;
import com.eshore.gringotts.web.domain.base.repository.SimpleRepository;
import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.list.ImmutableList;
/**
* @author lanyuanxiaoyao
* @date 2024-11-21
*/
public abstract class SimpleService<E, ID> {
protected abstract SimpleRepository<E, ID> repository();
public ImmutableList<E> list() {
return Lists.immutable.ofAll(repository().findAll());
}
public E detail(ID id) {
if (ObjectUtil.isNull(id)) {
return null;
}
return repository().findById(id).orElse(null);
}
}

View File

@@ -1,6 +1,10 @@
package com.eshore.gringotts.web.domain.resource.controller; package com.eshore.gringotts.web.domain.resource.controller;
import cn.hutool.core.util.EnumUtil; import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import com.eshore.gringotts.web.configuration.amis.AmisListResponse;
import com.eshore.gringotts.web.configuration.amis.AmisResponse;
import com.eshore.gringotts.web.domain.resource.entity.DataResource;
import com.eshore.gringotts.web.domain.resource.entity.format.CsvResourceFormat; import com.eshore.gringotts.web.domain.resource.entity.format.CsvResourceFormat;
import com.eshore.gringotts.web.domain.resource.entity.format.JsonLineResourceFormat; import com.eshore.gringotts.web.domain.resource.entity.format.JsonLineResourceFormat;
import com.eshore.gringotts.web.domain.resource.entity.format.JsonResourceFormat; import com.eshore.gringotts.web.domain.resource.entity.format.JsonResourceFormat;
@@ -14,13 +18,19 @@ import com.eshore.gringotts.web.domain.resource.entity.type.FtpResourceType;
import com.eshore.gringotts.web.domain.resource.entity.type.HDFSResourceType; import com.eshore.gringotts.web.domain.resource.entity.type.HDFSResourceType;
import com.eshore.gringotts.web.domain.resource.entity.type.ResourceType; import com.eshore.gringotts.web.domain.resource.entity.type.ResourceType;
import com.eshore.gringotts.web.domain.resource.service.DataResourceService; import com.eshore.gringotts.web.domain.resource.service.DataResourceService;
import com.eshore.gringotts.web.domain.upload.entity.DataFile;
import com.eshore.gringotts.web.domain.upload.service.DataFileService;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.LocalDateTime;
import java.util.Map; import java.util.Map;
import lombok.Data; import lombok.Data;
import org.slf4j.Logger; import lombok.EqualsAndHashCode;
import org.slf4j.LoggerFactory; import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@@ -32,90 +42,199 @@ import org.springframework.web.bind.annotation.RestController;
* @author lanyuanxiaoyao * @author lanyuanxiaoyao
* @date 2024-11-20 * @date 2024-11-20
*/ */
@Slf4j
@RestController @RestController
@RequestMapping("/data_resource") @RequestMapping("/data_resource")
public class DataResourceController { public class DataResourceController {
private static final Logger logger = LoggerFactory.getLogger(DataResourceController.class);
private final ObjectMapper mapper; private final ObjectMapper mapper;
private final DataResourceService dataResourceService; private final DataResourceService dataResourceService;
private final DataFileService dataFileService;
public DataResourceController(Jackson2ObjectMapperBuilder builder, DataResourceService dataResourceService) { public DataResourceController(Jackson2ObjectMapperBuilder builder, DataResourceService dataResourceService, DataFileService dataFileService) {
this.mapper = builder.build(); this.mapper = builder.build();
this.dataResourceService = dataResourceService; this.dataResourceService = dataResourceService;
this.dataFileService = dataFileService;
} }
@PostMapping("/create") @PostMapping("/create")
public void create(@RequestBody CreateRequest request) throws JsonProcessingException { public void create(@RequestBody CreateRequest request) throws JsonProcessingException {
logger.info("Create request: {}", request); log.info("Create request: {}", request);
ResourceType type = null; ResourceType type = null;
switch (request.resourceType) { switch (request.resourceType) {
case "api": case API:
type = new ApiResourceType(request.apiUrl, request.apiUsername, request.apiPassword); type = new ApiResourceType(request.apiUrl, request.apiUsername, request.apiPassword);
break; break;
case "file": case FILE:
type = new FileResourceType(request.filePath); DataFile dataFile = dataFileService.detail(request.fileId);
log.info("{}", dataFile);
type = new FileResourceType(dataFile);
break; break;
case "database": case DATABASE:
type = new DatabaseResourceType( type = new DatabaseResourceType(
request.databaseJdbc, request.databaseJdbc,
request.databaseUsername, request.databaseUsername,
request.databasePassword, request.databasePassword,
EnumUtil.fromString(DatabaseResourceType.Type.class, request.databaseType) EnumUtil.fromString(DatabaseResourceType.DatabaseType.class, request.databaseType)
); );
break; break;
case "hdfs": case HDFS:
type = new HDFSResourceType(request.coreSiteFile, request.hdfsSiteFile); type = new HDFSResourceType(dataFileService.detail(request.coreSiteFileId), dataFileService.detail(request.hdfsSiteFileId));
break; break;
case "ftp": case FTP:
type = new FtpResourceType(request.ftpUrl, request.ftpUsername, request.ftpPassword, request.ftpPath, request.ftpRegexFilter); type = new FtpResourceType(request.ftpUrl, request.ftpUsername, request.ftpPassword, request.ftpPath, request.ftpRegexFilter);
break; break;
} }
ResourceFormat format = null; ResourceFormat format = null;
switch (request.formatType) { switch (request.formatType) {
case "NONE": case NONE:
format = new NoneResourceFormat(); format = new NoneResourceFormat();
break; break;
case "LINE": case LINE:
format = new LineResourceFormat(); format = new LineResourceFormat();
break; break;
case "JSON": case JSON:
format = new JsonResourceFormat(mapper.writeValueAsString(request.jsonSchema)); format = new JsonResourceFormat(mapper.writeValueAsString(request.jsonSchema));
break; break;
case "JSON_LINE": case JSON_LINE:
format = new JsonLineResourceFormat(mapper.writeValueAsString(request.jsonLineSchema)); format = new JsonLineResourceFormat(mapper.writeValueAsString(request.jsonLineSchema));
break; break;
case "CSV": case CSV:
format = new CsvResourceFormat(mapper.writeValueAsString(request.csvSchema)); format = new CsvResourceFormat(mapper.writeValueAsString(request.csvSchema));
break; break;
} }
dataResourceService.create(request.name, request.description, format, type); dataResourceService.create(request.name, request.description, format, type, dataFileService.detail(request.exampleFileId));
}
@PostMapping("/list")
public AmisListResponse list() {
return AmisResponse.responseListData(dataResourceService.list().collect(DataResourceListItem::new));
}
@GetMapping("/detail/{id}")
public AmisResponse<DataResourceDetail> detail(@PathVariable Long id) throws JsonProcessingException {
return AmisResponse.responseSuccess(new DataResourceDetail(mapper, dataResourceService.detail(id)));
} }
@Data @Data
public static final class CreateRequest { public static class CreateRequest {
protected String name;
protected String description;
protected ResourceType.Type resourceType;
protected String apiUrl;
protected String apiUsername;
protected String apiPassword;
protected String fileId;
protected String databaseType;
protected String databaseJdbc;
protected String databaseUsername;
protected String databasePassword;
protected String coreSiteFileId;
protected String hdfsSiteFileId;
protected String ftpUrl;
protected String ftpUsername;
protected String ftpPassword;
protected String ftpPath;
protected String ftpRegexFilter;
protected ResourceFormat.Type formatType;
protected Map<?, ?> jsonSchema;
protected Map<?, ?> jsonLineSchema;
protected Map<?, ?> csvSchema;
protected String exampleFileId;
}
@Data
public static final class DataResourceListItem {
private Long id;
private String name; private String name;
private String description; private String description;
private String resourceType; private String type;
private String apiUrl; private String format;
private String apiUsername; private String createdUser;
private String apiPassword; private LocalDateTime createdTime;
private String filePath;
private String databaseType; public DataResourceListItem(DataResource dataResource) {
private String databaseJdbc; this.id = dataResource.getId();
private String databaseUsername; this.name = dataResource.getName();
private String databasePassword; this.description = dataResource.getDescription();
private String coreSiteFile; this.type = dataResource.getType().getResourceType().name();
private String hdfsSiteFile; this.format = dataResource.getFormat().getFormatType().name();
private String ftpUrl; this.createdUser = dataResource.getCreatedUser().getUsername();
private String ftpUsername; this.createdTime = dataResource.getCreatedTime();
private String ftpPassword; }
private String ftpPath; }
private String ftpRegexFilter;
private String formatType; @Data
private Map<?, ?> jsonSchema; @EqualsAndHashCode(callSuper = true)
private Map<?, ?> jsonLineSchema; @NoArgsConstructor
private Map<?, ?> csvSchema; public static final class DataResourceDetail extends CreateRequest {
private String example; private LocalDateTime createdTime;
private String createdUsername;
private LocalDateTime modifiedTime;
private String modifiedUsername;
public DataResourceDetail(ObjectMapper mapper, DataResource dataResource) throws JsonProcessingException {
log.info("DataResourceDetail: {}", dataResource);
this.name = dataResource.getName();
this.description = dataResource.getDescription();
this.resourceType = dataResource.getType().getResourceType();
switch (dataResource.getType().getResourceType()) {
case API:
ApiResourceType apiType = (ApiResourceType) dataResource.getType();
this.apiUrl = apiType.getUrl();
this.apiUsername = apiType.getUsername();
this.apiPassword = apiType.getPassword();
break;
case FILE:
FileResourceType fileType = (FileResourceType) dataResource.getType();
this.fileId = fileType.getFile().getFilename();
break;
case DATABASE:
DatabaseResourceType databaseType = (DatabaseResourceType) dataResource.getType();
this.databaseType = databaseType.getDatabaseType().name();
this.databaseJdbc = databaseType.getJdbc();
this.databaseUsername = databaseType.getUsername();
this.databasePassword = databaseType.getPassword();
break;
case HDFS:
HDFSResourceType hdfsType = (HDFSResourceType) dataResource.getType();
this.coreSiteFileId = hdfsType.getCoreSite().getFilename();
this.hdfsSiteFileId = hdfsType.getHdfsSite().getFilename();
break;
case FTP:
FtpResourceType ftpType = (FtpResourceType) dataResource.getType();
this.ftpUrl = ftpType.getUrl();
this.ftpUsername = ftpType.getUsername();
this.ftpPassword = ftpType.getPassword();
this.ftpPath = ftpType.getPath();
this.ftpRegexFilter = ftpType.getRegexFilter();
break;
}
this.formatType = dataResource.getFormat().getFormatType();
switch (dataResource.getFormat().getFormatType()) {
case NONE:
case LINE:
break;
case JSON:
JsonResourceFormat jsonFormat = (JsonResourceFormat) dataResource.getFormat();
this.jsonSchema = mapper.readValue(jsonFormat.getSchema(), Map.class);
break;
case JSON_LINE:
JsonLineResourceFormat jsonLineFormat = (JsonLineResourceFormat) dataResource.getFormat();
this.jsonLineSchema = mapper.readValue(jsonLineFormat.getSchema(), Map.class);
break;
case CSV:
CsvResourceFormat csvFormat = (CsvResourceFormat) dataResource.getFormat();
this.jsonLineSchema = mapper.readValue(csvFormat.getSchema(), Map.class);
break;
}
if (ObjectUtil.isNotNull(dataResource.getExample())) {
this.exampleFileId = dataResource.getExample().getFilename();
}
this.createdUsername = dataResource.getCreatedUser().getUsername();
this.createdTime = dataResource.getCreatedTime();
this.modifiedUsername = dataResource.getModifiedUser().getUsername();
this.modifiedTime = dataResource.getModifiedTime();
}
} }
} }

View File

@@ -13,6 +13,8 @@ import javax.persistence.EntityListeners;
import javax.persistence.FetchType; import javax.persistence.FetchType;
import javax.persistence.ForeignKey; import javax.persistence.ForeignKey;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.OneToOne; import javax.persistence.OneToOne;
import javax.persistence.Table; import javax.persistence.Table;
import lombok.Getter; import lombok.Getter;
@@ -28,6 +30,18 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
@EntityListeners(AuditingEntityListener.class) @EntityListeners(AuditingEntityListener.class)
@DynamicUpdate @DynamicUpdate
@Table(name = Constants.TABLE_PREFIX + "data_resource") @Table(name = Constants.TABLE_PREFIX + "data_resource")
@NamedEntityGraph(name = "data_resource.list", attributeNodes = {
@NamedAttributeNode(value = "type"),
@NamedAttributeNode(value = "format"),
@NamedAttributeNode(value = "createdUser"),
})
@NamedEntityGraph(name = "data_resource.detail", attributeNodes = {
@NamedAttributeNode(value = "type"),
@NamedAttributeNode(value = "format"),
@NamedAttributeNode(value = "example"),
@NamedAttributeNode(value = "createdUser"),
@NamedAttributeNode(value = "modifiedUser"),
})
public class DataResource extends SimpleEntity { public class DataResource extends SimpleEntity {
@Column(nullable = false) @Column(nullable = false)
private String name; private String name;

View File

@@ -4,6 +4,11 @@ import com.eshore.gringotts.core.Constants;
import com.eshore.gringotts.web.domain.upload.entity.DataFile; import com.eshore.gringotts.web.domain.upload.entity.DataFile;
import javax.persistence.ConstraintMode; import javax.persistence.ConstraintMode;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.JoinColumn;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.OneToOne;
import javax.persistence.Table; import javax.persistence.Table;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
@@ -18,6 +23,9 @@ import lombok.ToString;
@NoArgsConstructor @NoArgsConstructor
@Entity @Entity
@Table(name = Constants.TABLE_PREFIX + "resource_type_file") @Table(name = Constants.TABLE_PREFIX + "resource_type_file")
@NamedEntityGraph(name = "file_resource_type.detail", attributeNodes = {
@NamedAttributeNode(value = "file")
})
public class FileResourceType extends ResourceType { public class FileResourceType extends ResourceType {
@OneToOne @OneToOne
@JoinColumn(nullable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) @JoinColumn(nullable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))

View File

@@ -4,6 +4,11 @@ import com.eshore.gringotts.core.Constants;
import com.eshore.gringotts.web.domain.upload.entity.DataFile; import com.eshore.gringotts.web.domain.upload.entity.DataFile;
import javax.persistence.ConstraintMode; import javax.persistence.ConstraintMode;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.JoinColumn;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.OneToOne;
import javax.persistence.Table; import javax.persistence.Table;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
@@ -18,6 +23,10 @@ import lombok.ToString;
@NoArgsConstructor @NoArgsConstructor
@Entity @Entity
@Table(name = Constants.TABLE_PREFIX + "resource_type_hdfs") @Table(name = Constants.TABLE_PREFIX + "resource_type_hdfs")
@NamedEntityGraph(name = "hdfs_resource_type.detail", attributeNodes = {
@NamedAttributeNode(value = "coreSite"),
@NamedAttributeNode(value = "hdfsSite"),
})
public class HDFSResourceType extends ResourceType { public class HDFSResourceType extends ResourceType {
@OneToOne @OneToOne
@JoinColumn(nullable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) @JoinColumn(nullable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))

View File

@@ -2,8 +2,19 @@ package com.eshore.gringotts.web.domain.resource.repository;
import com.eshore.gringotts.web.domain.base.repository.SimpleRepository; import com.eshore.gringotts.web.domain.base.repository.SimpleRepository;
import com.eshore.gringotts.web.domain.resource.entity.DataResource; import com.eshore.gringotts.web.domain.resource.entity.DataResource;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@SuppressWarnings("NullableProblems")
@Repository @Repository
public interface DataResourceRepository extends SimpleRepository<DataResource, Long> { public interface DataResourceRepository extends SimpleRepository<DataResource, Long> {
@Override
@EntityGraph(value = "data_resource.list", type = EntityGraph.EntityGraphType.FETCH)
List<DataResource> findAll();
@Override
@EntityGraph(value = "data_resource.detail", type = EntityGraph.EntityGraphType.FETCH)
Optional<DataResource> findById(Long id);
} }

View File

@@ -1,16 +1,18 @@
package com.eshore.gringotts.web.domain.resource.service; package com.eshore.gringotts.web.domain.resource.service;
import com.eshore.gringotts.web.domain.base.repository.SimpleRepository;
import com.eshore.gringotts.web.domain.base.service.SimpleService;
import com.eshore.gringotts.web.domain.resource.entity.DataResource; import com.eshore.gringotts.web.domain.resource.entity.DataResource;
import com.eshore.gringotts.web.domain.resource.entity.format.ResourceFormat; import com.eshore.gringotts.web.domain.resource.entity.format.ResourceFormat;
import com.eshore.gringotts.web.domain.resource.entity.type.ResourceType; import com.eshore.gringotts.web.domain.resource.entity.type.ResourceType;
import com.eshore.gringotts.web.domain.resource.repository.DataResourceRepository; import com.eshore.gringotts.web.domain.resource.repository.DataResourceRepository;
import com.eshore.gringotts.web.domain.resource.repository.ResourceFormatRepository; import com.eshore.gringotts.web.domain.resource.repository.ResourceFormatRepository;
import com.eshore.gringotts.web.domain.resource.repository.ResourceTypeRepository; import com.eshore.gringotts.web.domain.resource.repository.ResourceTypeRepository;
import com.eshore.gringotts.web.domain.upload.entity.DataFile;
import com.eshore.gringotts.web.domain.user.entity.User; import com.eshore.gringotts.web.domain.user.entity.User;
import com.eshore.gringotts.web.domain.user.service.UserService; import com.eshore.gringotts.web.domain.user.service.UserService;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import org.slf4j.Logger; import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
/** /**
@@ -18,10 +20,9 @@ import org.springframework.stereotype.Service;
* *
* @author lanyuanxiaoyao * @author lanyuanxiaoyao
*/ */
@Slf4j
@Service @Service
public class DataResourceService { public class DataResourceService extends SimpleService<DataResource, Long> {
private static final Logger log = LoggerFactory.getLogger(DataResourceService.class);
private final DataResourceRepository dataResourceRepository; private final DataResourceRepository dataResourceRepository;
private final ResourceTypeRepository resourceTypeRepository; private final ResourceTypeRepository resourceTypeRepository;
private final ResourceFormatRepository resourceFormatRepository; private final ResourceFormatRepository resourceFormatRepository;
@@ -34,15 +35,22 @@ public class DataResourceService {
this.userService = userService; this.userService = userService;
} }
@Override
protected SimpleRepository<DataResource, Long> repository() {
return dataResourceRepository;
}
@Transactional @Transactional
public void create(String name, String description, ResourceFormat format, ResourceType type) { public void create(String name, String description, ResourceFormat format, ResourceType type, DataFile example) {
resourceFormatRepository.save(format); resourceFormatRepository.save(format);
log.info("{}", type);
resourceTypeRepository.save(type); resourceTypeRepository.save(type);
DataResource resource = new DataResource(); DataResource resource = new DataResource();
resource.setName(name); resource.setName(name);
resource.setDescription(description); resource.setDescription(description);
resource.setFormat(format); resource.setFormat(format);
resource.setType(type); resource.setType(type);
resource.setExample(example);
User user = userService.currentLoginUser(); User user = userService.currentLoginUser();
resource.setCreatedUser(user); resource.setCreatedUser(user);
resource.setModifiedUser(user); resource.setModifiedUser(user);

View File

@@ -5,7 +5,7 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.SecureUtil;
import com.eshore.gringotts.web.configuration.UploadConfiguration; import com.eshore.gringotts.web.configuration.UploadConfiguration;
import com.eshore.gringotts.web.configuration.amis.AmisResponse; import com.eshore.gringotts.web.configuration.amis.AmisResponse;
import com.eshore.gringotts.web.domain.upload.service.UploadService; import com.eshore.gringotts.web.domain.upload.service.DataFileService;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
@@ -37,13 +37,13 @@ import org.springframework.web.multipart.MultipartFile;
public class UploadController { public class UploadController {
private static final Logger logger = LoggerFactory.getLogger(UploadController.class); private static final Logger logger = LoggerFactory.getLogger(UploadController.class);
private final UploadService uploadService; private final DataFileService dataFileService;
private final String uploadFolderPath; private final String uploadFolderPath;
private final String cacheFolderPath; private final String cacheFolderPath;
private final String sliceFolderPath; private final String sliceFolderPath;
public UploadController(UploadConfiguration uploadConfiguration, UploadService uploadService) { public UploadController(UploadConfiguration uploadConfiguration, DataFileService dataFileService) {
this.uploadService = uploadService; this.dataFileService = dataFileService;
this.uploadFolderPath = uploadConfiguration.getUploadPath(); this.uploadFolderPath = uploadConfiguration.getUploadPath();
this.cacheFolderPath = StrUtil.format("{}/cache", uploadFolderPath); this.cacheFolderPath = StrUtil.format("{}/cache", uploadFolderPath);
@@ -53,7 +53,7 @@ public class UploadController {
@PostMapping("/start") @PostMapping("/start")
public AmisResponse<StartResponse> start(@RequestBody StartRequest request) { public AmisResponse<StartResponse> start(@RequestBody StartRequest request) {
logger.info("Request: {}", request); logger.info("Request: {}", request);
Long id = uploadService.initialDataFile(request.filename); Long id = dataFileService.initialDataFile(request.filename);
return AmisResponse.responseSuccess(new StartResponse(id.toString())); return AmisResponse.responseSuccess(new StartResponse(id.toString()));
} }
@@ -68,7 +68,6 @@ public class UploadController {
@RequestParam("file") @RequestParam("file")
MultipartFile file MultipartFile file
) throws IOException { ) throws IOException {
logger.info("UploadId: {}, sequence: {}, size: {}, file: {}", uploadId, sequence, size, file.getName());
byte[] bytes = file.getBytes(); byte[] bytes = file.getBytes();
String md5 = SecureUtil.md5(new ByteArrayInputStream(bytes)); String md5 = SecureUtil.md5(new ByteArrayInputStream(bytes));
String targetFilename = StrUtil.format("{}-{}", sequence, md5); String targetFilename = StrUtil.format("{}-{}", sequence, md5);
@@ -84,7 +83,6 @@ public class UploadController {
@PostMapping("finish") @PostMapping("finish")
public AmisResponse<FinishResponse> finish(@RequestBody FinishRequest request) { public AmisResponse<FinishResponse> finish(@RequestBody FinishRequest request) {
logger.info("Request: {}", request);
if (request.partList.anySatisfy(part -> !FileUtil.exist(sliceFilePath(request.uploadId, part.eTag)))) { if (request.partList.anySatisfy(part -> !FileUtil.exist(sliceFilePath(request.uploadId, part.eTag)))) {
throw new RuntimeException("文件校验失败,请重新上传"); throw new RuntimeException("文件校验失败,请重新上传");
} }
@@ -104,9 +102,12 @@ public class UploadController {
} }
} }
} }
File targetFile = new File(StrUtil.format("{}/{}", uploadFolderPath, request.uploadId)); String md5 = SecureUtil.md5(cacheFile);
FileUtil.move(cacheFile, targetFile, true); File targetFile = new File(StrUtil.format("{}/{}", uploadFolderPath, md5));
uploadService.updateDataFile(request.uploadId, FileUtil.getAbsolutePath(targetFile), FileUtil.size(targetFile), SecureUtil.md5(targetFile)); if (!targetFile.exists()) {
FileUtil.move(cacheFile, targetFile, true);
}
dataFileService.updateDataFile(request.uploadId, FileUtil.getAbsolutePath(targetFile), FileUtil.size(targetFile), SecureUtil.md5(targetFile));
return AmisResponse.responseSuccess(new FinishResponse(request.uploadId.toString())); return AmisResponse.responseSuccess(new FinishResponse(request.uploadId.toString()));
} else { } else {
throw new RuntimeException("合并文件失败"); throw new RuntimeException("合并文件失败");
@@ -114,6 +115,7 @@ public class UploadController {
} catch (Throwable throwable) { } catch (Throwable throwable) {
throw new RuntimeException(throwable); throw new RuntimeException(throwable);
} finally { } finally {
FileUtil.del(StrUtil.format("{}/{}", cacheFolderPath, request.uploadId));
FileUtil.del(StrUtil.format("{}/{}", sliceFolderPath, request.uploadId)); FileUtil.del(StrUtil.format("{}/{}", sliceFolderPath, request.uploadId));
} }
} }

View File

@@ -1,6 +1,6 @@
package com.eshore.gringotts.web.domain.upload.entity; package com.eshore.gringotts.web.domain.upload.entity;
import com.eshore.gringotts.web.domain.entity.SimpleEntity; import com.eshore.gringotts.web.domain.base.entity.SimpleEntity;
import javax.persistence.Entity; import javax.persistence.Entity;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;

View File

@@ -1,5 +1,7 @@
package com.eshore.gringotts.web.domain.upload.service; package com.eshore.gringotts.web.domain.upload.service;
import com.eshore.gringotts.web.domain.base.repository.SimpleRepository;
import com.eshore.gringotts.web.domain.base.service.SimpleService;
import com.eshore.gringotts.web.domain.upload.entity.DataFile; import com.eshore.gringotts.web.domain.upload.entity.DataFile;
import com.eshore.gringotts.web.domain.upload.repository.DataFileRepository; import com.eshore.gringotts.web.domain.upload.repository.DataFileRepository;
import com.eshore.gringotts.web.domain.user.entity.User; import com.eshore.gringotts.web.domain.user.entity.User;
@@ -15,17 +17,29 @@ import org.springframework.stereotype.Service;
* @date 2024-11-21 * @date 2024-11-21
*/ */
@Service @Service
public class UploadService { public class DataFileService extends SimpleService<DataFile, Long> {
private static final Logger logger = LoggerFactory.getLogger(UploadService.class); private static final Logger logger = LoggerFactory.getLogger(DataFileService.class);
private final DataFileRepository dataFileRepository; private final DataFileRepository dataFileRepository;
private final UserService userService; private final UserService userService;
public UploadService(DataFileRepository dataFileRepository, UserService userService) { public DataFileService(DataFileRepository dataFileRepository, UserService userService) {
this.dataFileRepository = dataFileRepository; this.dataFileRepository = dataFileRepository;
this.userService = userService; this.userService = userService;
} }
@Override
protected SimpleRepository<DataFile, Long> repository() {
return dataFileRepository;
}
public DataFile detail(String id) {
if (id == null) {
return null;
}
return detail(Long.valueOf(id));
}
public Long initialDataFile(String filename) { public Long initialDataFile(String filename) {
DataFile dataFile = new DataFile(); DataFile dataFile = new DataFile();
dataFile.setFilename(filename); dataFile.setFilename(filename);
@@ -45,6 +59,12 @@ public class UploadService {
dataFileRepository.save(dataFile); dataFileRepository.save(dataFile);
} }
public static final class DataFileNotFoundException extends RuntimeException {
public DataFileNotFoundException() {
super("文件未找到,请重新上传");
}
}
public static final class UpdateDataFileFailedException extends RuntimeException { public static final class UpdateDataFileFailedException extends RuntimeException {
public UpdateDataFileFailedException() { public UpdateDataFileFailedException() {
super("更新文件信息失败,请重新上传"); super("更新文件信息失败,请重新上传");

View File

@@ -1,7 +1,7 @@
package com.eshore.gringotts.web.domain.user.entity; package com.eshore.gringotts.web.domain.user.entity;
import com.eshore.gringotts.core.Constants; import com.eshore.gringotts.core.Constants;
import com.eshore.gringotts.web.domain.entity.SimpleEntity; import com.eshore.gringotts.web.domain.base.entity.SimpleEntity;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.ConstraintMode; import javax.persistence.ConstraintMode;
@@ -11,6 +11,8 @@ import javax.persistence.Enumerated;
import javax.persistence.FetchType; import javax.persistence.FetchType;
import javax.persistence.ForeignKey; import javax.persistence.ForeignKey;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.OneToOne; import javax.persistence.OneToOne;
import javax.persistence.Table; import javax.persistence.Table;
import lombok.Getter; import lombok.Getter;
@@ -30,6 +32,14 @@ import org.hibernate.annotations.DynamicUpdate;
@Entity @Entity
@DynamicUpdate @DynamicUpdate
@Table(name = Constants.TABLE_PREFIX + "user") @Table(name = Constants.TABLE_PREFIX + "user")
@NamedEntityGraph(name = "user.list", attributeNodes = {
@NamedAttributeNode(value = "createdUser"),
})
@NamedEntityGraph(name = "user.detail", attributeNodes = {
@NamedAttributeNode(value = "createdUser"),
@NamedAttributeNode(value = "modifiedUser"),
@NamedAttributeNode(value = "checkedUser"),
})
public class User extends SimpleEntity { public class User extends SimpleEntity {
@Column(unique = true, nullable = false) @Column(unique = true, nullable = false)
private String username; private String username;

View File

@@ -1,14 +1,11 @@
package com.eshore.gringotts.web.domain.user.repository; package com.eshore.gringotts.web.domain.user.repository;
import com.blinkfox.fenix.jpa.FenixJpaRepository;
import com.blinkfox.fenix.specification.FenixJpaSpecificationExecutor;
import com.eshore.gringotts.web.domain.base.repository.SimpleRepository; import com.eshore.gringotts.web.domain.base.repository.SimpleRepository;
import com.eshore.gringotts.web.domain.user.entity.User; import com.eshore.gringotts.web.domain.user.entity.User;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
/** /**
* User操作 * User操作
@@ -16,8 +13,14 @@ import org.springframework.transaction.annotation.Transactional;
* @author lanyuanxiaoyao * @author lanyuanxiaoyao
* @date 2024-11-14 * @date 2024-11-14
*/ */
@SuppressWarnings("NullableProblems")
@Repository @Repository
public interface UserRepository extends SimpleRepository<User, Long> { public interface UserRepository extends SimpleRepository<User, Long> {
@Override
@EntityGraph(value = "user.list", type = EntityGraph.EntityGraphType.FETCH)
List<User> findAll();
Boolean existsByUsername(String username); Boolean existsByUsername(String username);
@EntityGraph(value = "user.detail", type = EntityGraph.EntityGraphType.FETCH)
Optional<User> findByUsername(String username); Optional<User> findByUsername(String username);
} }