feat: support upload driver from local
This commit is contained in:
parent
38ad685fb7
commit
15a9f4ae18
|
@ -12,6 +12,7 @@ import org.springframework.data.web.PageableDefault;
|
|||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
@ -80,4 +81,11 @@ public class DatabaseTypeController {
|
|||
return JsonData.ok(driverClassName);
|
||||
}
|
||||
|
||||
@PostMapping(Routes.DatabaseType.UPLOAD_DRIVER)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER')")
|
||||
public JsonData<String> uploadDriver(@RequestPart MultipartFile file) {
|
||||
String driverPath = databaseTypeService.uploadDriver(file);
|
||||
return JsonData.ok(driverPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,9 @@ spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
|||
spring.datasource.username=${databasir.db.username}
|
||||
spring.datasource.password=${databasir.db.password}
|
||||
spring.datasource.url=jdbc:mysql://${databasir.db.url}/${databasir.db.name:databasir}
|
||||
spring.servlet.multipart.max-file-size=100MB
|
||||
spring.servlet.multipart.max-request-size=100MB
|
||||
spring.web.resources.static-locations=
|
||||
# jooq
|
||||
spring.jooq.sql-dialect=mysql
|
||||
# flyway
|
||||
|
|
|
@ -45,7 +45,11 @@ public enum DomainErrors implements DatabasirErrors {
|
|||
INVALID_MOCK_DATA_SCRIPT("A_10029", "不合法的表达式"),
|
||||
CANNOT_DELETE_SELF("A_10030", "无法对自己执行删除账号操作"),
|
||||
DRIVER_CLASS_NOT_FOUND("A_10031", "获取驱动类名失败"),
|
||||
DATABASE_DOCUMENT_DUPLICATE_KEY("A_10032", "文档版本重复");
|
||||
DATABASE_DOCUMENT_DUPLICATE_KEY("A_10032", "文档版本重复"),
|
||||
UPLOAD_DRIVER_FILE_ERROR("A_10033", "上传失败,请检查后重新上传"),
|
||||
|
||||
DRIVER_URL_AND_PATH_MUST_NOT_BE_ALL_BLANK("A_10034", "请填写下载驱动的地址或手动上传驱动文件"),
|
||||
;
|
||||
|
||||
private final String errCode;
|
||||
|
||||
|
|
|
@ -14,10 +14,14 @@ public interface DatabaseTypePojoConverter {
|
|||
@Mapping(target = "id", ignore = true)
|
||||
@Mapping(target = "updateAt", ignore = true)
|
||||
@Mapping(target = "createAt", ignore = true)
|
||||
@Mapping(target = "jdbcDriverFilePath", source = "jdbcDriverFilePath")
|
||||
DatabaseTypePojo of(DatabaseTypeCreateRequest request, String jdbcDriverFilePath);
|
||||
|
||||
@Mapping(target = "jdbcDriverFilePath", source = "jdbcDriverFilePath")
|
||||
DatabaseTypePojo of(DatabaseTypeUpdateRequest request, String jdbcDriverFilePath);
|
||||
|
||||
DatabaseTypePojo of(DatabaseTypeUpdateRequest request);
|
||||
|
||||
DatabaseTypeDetailResponse toDetailResponse(DatabaseTypePojo data);
|
||||
|
||||
DatabaseTypePageResponse toPageResponse(DatabaseTypePojo pojo, Integer projectCount);
|
||||
|
|
|
@ -15,9 +15,10 @@ public class DatabaseTypeCreateRequest {
|
|||
@NotBlank
|
||||
private String description;
|
||||
|
||||
@NotBlank
|
||||
private String jdbcDriverFileUrl;
|
||||
|
||||
private String jdbcDriverFilePath;
|
||||
|
||||
@NotBlank
|
||||
private String jdbcDriverClassName;
|
||||
|
||||
|
|
|
@ -19,9 +19,10 @@ public class DatabaseTypeUpdateRequest {
|
|||
@NotBlank
|
||||
private String description;
|
||||
|
||||
@NotBlank
|
||||
private String jdbcDriverFileUrl;
|
||||
|
||||
private String jdbcDriverFilePath;
|
||||
|
||||
@NotBlank
|
||||
private String jdbcDriverClassName;
|
||||
|
||||
|
|
|
@ -2,14 +2,12 @@ package com.databasir.core.domain.database.data;
|
|||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Data
|
||||
public class DriverClassNameResolveRequest {
|
||||
|
||||
private String databaseType;
|
||||
|
||||
@NotBlank
|
||||
private String jdbcDriverFileUrl;
|
||||
|
||||
private String jdbcDriverFilePath;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.databasir.core.domain.database.service;
|
|||
import com.databasir.core.domain.DomainErrors;
|
||||
import com.databasir.core.domain.database.converter.DatabaseTypePojoConverter;
|
||||
import com.databasir.core.domain.database.data.*;
|
||||
import com.databasir.core.domain.database.validator.DatabaseTypeUpdateValidator;
|
||||
import com.databasir.core.infrastructure.connection.DatabaseTypes;
|
||||
import com.databasir.core.infrastructure.driver.DriverResources;
|
||||
import com.databasir.core.infrastructure.driver.DriverResult;
|
||||
|
@ -11,15 +12,20 @@ import com.databasir.dao.impl.ProjectDao;
|
|||
import com.databasir.dao.tables.pojos.DatabaseTypePojo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -36,14 +42,29 @@ public class DatabaseTypeService {
|
|||
|
||||
private final DatabaseTypePojoConverter databaseTypePojoConverter;
|
||||
|
||||
private final DatabaseTypeUpdateValidator databaseTypeUpdateValidator;
|
||||
|
||||
|
||||
/**
|
||||
* 1. validate: filePath, fileUrl
|
||||
* 2. validate: databaseType
|
||||
* 3. load from remote or local
|
||||
* 4. validate driver class name
|
||||
* 5. copy to standard directory
|
||||
* 6. save to database
|
||||
*/
|
||||
public Integer create(DatabaseTypeCreateRequest request) {
|
||||
if (databaseTypeDao.existsByDatabaseType(request.getDatabaseType())) {
|
||||
databaseTypeUpdateValidator.validRequestRequiredParams(request);
|
||||
String databaseType = request.getDatabaseType();
|
||||
if (databaseTypeDao.existsByDatabaseType(databaseType)) {
|
||||
throw DomainErrors.DATABASE_TYPE_NAME_DUPLICATE.exception();
|
||||
}
|
||||
DriverResult result =
|
||||
driverResources.load(null, request.getJdbcDriverFileUrl(), request.getDatabaseType());
|
||||
driverResources.validateDriverJar(result.getDriverFile(), request.getJdbcDriverClassName());
|
||||
DatabaseTypePojo pojo = databaseTypePojoConverter.of(request, result.getDriverFilePath());
|
||||
DriverResult result = loadAndValidate(request.getJdbcDriverFileUrl(),
|
||||
request.getJdbcDriverFilePath(), request.getJdbcDriverClassName());
|
||||
String targetPath = driverResources.copyToStandardDirectory(result.getDriverFile(), databaseType);
|
||||
DatabaseTypePojo pojo = databaseTypePojoConverter.of(request, targetPath);
|
||||
// TODO workaround
|
||||
pojo.setJdbcDriverFileUrl(StringUtils.defaultIfBlank(request.getJdbcDriverFileUrl(), ""));
|
||||
try {
|
||||
return databaseTypeDao.insertAndReturnId(pojo);
|
||||
} catch (DuplicateKeyException e) {
|
||||
|
@ -53,20 +74,23 @@ public class DatabaseTypeService {
|
|||
|
||||
@Transactional
|
||||
public void update(DatabaseTypeUpdateRequest request) {
|
||||
databaseTypeUpdateValidator.validRequestRequiredParams(request);
|
||||
databaseTypeDao.selectOptionalById(request.getId()).ifPresent(data -> {
|
||||
databaseTypeUpdateValidator.validDatabaseTypeIfNecessary(request, data);
|
||||
String databaseType = request.getDatabaseType();
|
||||
DatabaseTypePojo pojo;
|
||||
if (!Objects.equals(request.getDatabaseType(), data.getDatabaseType())
|
||||
|| !Objects.equals(request.getJdbcDriverFileUrl(), data.getJdbcDriverFileUrl())) {
|
||||
if (databaseTypeUpdateValidator.shouldReloadDriver(request, data)) {
|
||||
// 名称修改,下载地址修改需要删除原有的 driver 并重新下载验证
|
||||
driverResources.deleteByDatabaseType(data.getDatabaseType());
|
||||
// download
|
||||
DriverResult result =
|
||||
driverResources.load(null, request.getJdbcDriverFileUrl(), request.getDatabaseType());
|
||||
driverResources.validateDriverJar(result.getDriverFile(), request.getJdbcDriverClassName());
|
||||
// validate
|
||||
pojo = databaseTypePojoConverter.of(request, result.getDriverFilePath());
|
||||
DriverResult result = loadAndValidate(request.getJdbcDriverFileUrl(),
|
||||
request.getJdbcDriverFilePath(), request.getJdbcDriverClassName());
|
||||
String targetPath = driverResources.copyToStandardDirectory(result.getDriverFile(), databaseType);
|
||||
pojo = databaseTypePojoConverter.of(request, targetPath);
|
||||
pojo.setJdbcDriverFileUrl(StringUtils.defaultIfBlank(request.getJdbcDriverFileUrl(), ""));
|
||||
} else {
|
||||
pojo = databaseTypePojoConverter.of(request, data.getJdbcDriverFilePath());
|
||||
pojo = databaseTypePojoConverter.of(request);
|
||||
pojo.setJdbcDriverFileUrl(StringUtils.defaultIfBlank(request.getJdbcDriverFileUrl(), ""));
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -77,6 +101,17 @@ public class DatabaseTypeService {
|
|||
});
|
||||
}
|
||||
|
||||
private DriverResult loadAndValidate(String remoteUrl, String localPath, String className) {
|
||||
DriverResult result;
|
||||
if (StringUtils.isNoneBlank(localPath)) {
|
||||
result = driverResources.loadFromLocal(localPath);
|
||||
} else {
|
||||
result = driverResources.loadFromRemote(remoteUrl);
|
||||
}
|
||||
driverResources.validateDriverJar(result.getDriverFile(), className);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void deleteById(Integer id) {
|
||||
databaseTypeDao.selectOptionalById(id).ifPresent(data -> {
|
||||
if (DatabaseTypes.has(data.getDatabaseType())) {
|
||||
|
@ -120,7 +155,25 @@ public class DatabaseTypeService {
|
|||
}
|
||||
|
||||
public String resolveDriverClassName(DriverClassNameResolveRequest request) {
|
||||
return driverResources.resolveDriverClassName(request.getJdbcDriverFileUrl());
|
||||
databaseTypeUpdateValidator.validRequestRequiredParams(request);
|
||||
if (StringUtils.isNotBlank(request.getJdbcDriverFileUrl())) {
|
||||
return driverResources.resolveDriverClassNameFromRemote(request.getJdbcDriverFileUrl());
|
||||
} else {
|
||||
return driverResources.resolveDriverClassNameFromLocal(request.getJdbcDriverFilePath());
|
||||
}
|
||||
}
|
||||
|
||||
public String uploadDriver(MultipartFile file) {
|
||||
String parent = "temp";
|
||||
String path = parent + "/" + System.currentTimeMillis() + "-" + file.getOriginalFilename();
|
||||
try {
|
||||
Files.createDirectories(Paths.get(parent));
|
||||
Path targetPath = Paths.get(path);
|
||||
Files.copy(file.getInputStream(), targetPath);
|
||||
return path;
|
||||
} catch (IOException e) {
|
||||
log.error("upload driver file error", e);
|
||||
throw DomainErrors.UPLOAD_DRIVER_FILE_ERROR.exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package com.databasir.core.domain.database.validator;
|
||||
|
||||
import com.databasir.core.domain.DomainErrors;
|
||||
import com.databasir.core.domain.database.data.DatabaseTypeCreateRequest;
|
||||
import com.databasir.core.domain.database.data.DatabaseTypeUpdateRequest;
|
||||
import com.databasir.core.domain.database.data.DriverClassNameResolveRequest;
|
||||
import com.databasir.dao.impl.DatabaseTypeDao;
|
||||
import com.databasir.dao.tables.pojos.DatabaseTypePojo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DatabaseTypeUpdateValidator {
|
||||
|
||||
private final DatabaseTypeDao databaseTypeDao;
|
||||
|
||||
public void validRequestRequiredParams(DatabaseTypeCreateRequest request) {
|
||||
if (StringUtils.isAllBlank(request.getJdbcDriverFilePath(), request.getJdbcDriverFileUrl())) {
|
||||
throw DomainErrors.DRIVER_URL_AND_PATH_MUST_NOT_BE_ALL_BLANK.exception();
|
||||
}
|
||||
}
|
||||
|
||||
public void validRequestRequiredParams(DatabaseTypeUpdateRequest request) {
|
||||
if (StringUtils.isAllBlank(request.getJdbcDriverFilePath(), request.getJdbcDriverFileUrl())) {
|
||||
throw DomainErrors.DRIVER_URL_AND_PATH_MUST_NOT_BE_ALL_BLANK.exception();
|
||||
}
|
||||
}
|
||||
|
||||
public void validRequestRequiredParams(DriverClassNameResolveRequest request) {
|
||||
if (StringUtils.isAllBlank(request.getJdbcDriverFilePath(), request.getJdbcDriverFileUrl())) {
|
||||
throw DomainErrors.DRIVER_URL_AND_PATH_MUST_NOT_BE_ALL_BLANK.exception();
|
||||
}
|
||||
}
|
||||
|
||||
public void validDatabaseTypeIfNecessary(DatabaseTypeUpdateRequest request, DatabaseTypePojo origin) {
|
||||
if (!Objects.equals(request.getDatabaseType(), origin.getDatabaseType())) {
|
||||
if (databaseTypeDao.existsByDatabaseType(request.getDatabaseType())) {
|
||||
throw DomainErrors.DATABASE_TYPE_NAME_DUPLICATE.exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldReloadDriver(DatabaseTypeUpdateRequest request, DatabaseTypePojo origin) {
|
||||
if (!Objects.equals(request.getDatabaseType(), origin.getDatabaseType())) {
|
||||
return true;
|
||||
}
|
||||
if (!Objects.equals(request.getJdbcDriverFileUrl(), origin.getJdbcDriverFileUrl())) {
|
||||
return true;
|
||||
}
|
||||
if (!Objects.equals(request.getJdbcDriverFilePath(), origin.getJdbcDriverFilePath())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
package com.databasir.core.infrastructure.connection;
|
||||
|
||||
import com.alibaba.excel.util.StringUtils;
|
||||
import com.databasir.core.domain.DomainErrors;
|
||||
import com.databasir.core.infrastructure.driver.DriverResources;
|
||||
import com.databasir.core.infrastructure.driver.DriverResult;
|
||||
import com.databasir.dao.impl.DatabaseTypeDao;
|
||||
import com.databasir.dao.tables.pojos.DatabaseTypePojo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
@ -15,10 +15,10 @@ import java.lang.reflect.InvocationTargetException;
|
|||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
|
||||
@Component
|
||||
|
@ -83,14 +83,16 @@ public class CustomDatabaseConnectionFactory implements DatabaseConnectionFactor
|
|||
}
|
||||
|
||||
private File loadDriver(DatabaseTypePojo type) {
|
||||
if (StringUtils.isNotBlank(type.getJdbcDriverFilePath())) {
|
||||
return driverResources.loadFromLocal(type.getJdbcDriverFilePath()).getDriverFile();
|
||||
}
|
||||
if (StringUtils.isNotBlank(type.getJdbcDriverFileUrl())) {
|
||||
File remoteFile = driverResources.loadFromRemote(type.getJdbcDriverFileUrl()).getDriverFile();
|
||||
driverResources.validateDriverJar(remoteFile, type.getJdbcDriverClassName());
|
||||
String targetFile = driverResources.copyToStandardDirectory(remoteFile, type.getDatabaseType());
|
||||
return Paths.get(targetFile).toFile();
|
||||
}
|
||||
String databaseType = type.getDatabaseType();
|
||||
String file = type.getJdbcDriverFilePath();
|
||||
String url = type.getJdbcDriverFileUrl();
|
||||
DriverResult result = driverResources.load(file, url, databaseType);
|
||||
File driverFile = result.getDriverFile();
|
||||
if (!Objects.equals(result.getDriverFilePath(), type.getJdbcDriverFilePath())) {
|
||||
databaseTypeDao.updateDriverFile(type.getId(), result.getDriverFilePath());
|
||||
}
|
||||
return driverFile;
|
||||
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception("驱动加载失败, database=" + databaseType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.net.URLClassLoader;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.UUID;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
|
@ -32,6 +33,21 @@ public class DriverResources {
|
|||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
public DriverResult loadFromLocal(String localPath) {
|
||||
File driverFile = Paths.get(localPath).toFile();
|
||||
if (driverFile.exists()) {
|
||||
return new DriverResult(localPath, driverFile);
|
||||
} else {
|
||||
throw DomainErrors.UPLOAD_DRIVER_FILE_ERROR.exception();
|
||||
}
|
||||
}
|
||||
|
||||
public DriverResult loadFromRemote(String remoteUrl) {
|
||||
String targetFile = "temp/" + System.currentTimeMillis() + ".jar";
|
||||
File file = download(remoteUrl, targetFile);
|
||||
return new DriverResult(targetFile, file);
|
||||
}
|
||||
|
||||
public DriverResult load(String driverFilePath, String driverFileUrl, String databaseType) {
|
||||
if (driverFilePath == null) {
|
||||
String targetFile = targetDriverFile(databaseType);
|
||||
|
@ -105,7 +121,7 @@ public class DriverResources {
|
|||
}
|
||||
}
|
||||
|
||||
public String resolveDriverClassName(String driverFileUrl) {
|
||||
public String resolveDriverClassNameFromRemote(String driverFileUrl) {
|
||||
String tempFilePath = "temp/" + UUID.randomUUID() + ".jar";
|
||||
File driverFile = download(driverFileUrl, tempFilePath);
|
||||
String className = resolveDriverClassName(driverFile);
|
||||
|
@ -117,6 +133,14 @@ public class DriverResources {
|
|||
return className;
|
||||
}
|
||||
|
||||
public String resolveDriverClassNameFromLocal(String driverFilePath) {
|
||||
File driverFile = Paths.get(driverFilePath).toFile();
|
||||
if (!driverFile.exists()) {
|
||||
throw DomainErrors.DRIVER_CLASS_NOT_FOUND.exception("驱动文件不存在,请重新上传");
|
||||
}
|
||||
return resolveDriverClassName(driverFile);
|
||||
}
|
||||
|
||||
public String resolveDriverClassName(File driverFile) {
|
||||
JarFile jarFile = null;
|
||||
try {
|
||||
|
@ -177,6 +201,19 @@ public class DriverResources {
|
|||
}
|
||||
}
|
||||
|
||||
public String copyToStandardDirectory(File sourceFile, String databaseType) {
|
||||
String targetFile = targetDriverFile(databaseType);
|
||||
try {
|
||||
Path target = Paths.get(targetFile);
|
||||
Files.createDirectories(target.getParent());
|
||||
Files.copy(sourceFile.toPath(), target, StandardCopyOption.REPLACE_EXISTING);
|
||||
return targetFile;
|
||||
} catch (IOException e) {
|
||||
log.error("copy driver file error", e);
|
||||
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String targetDriverFile(String databaseType) {
|
||||
return driverBaseDirectory
|
||||
+ "/" + databaseType
|
||||
|
|
|
@ -38,6 +38,10 @@ class DatabaseTypeServiceTest extends BaseTest {
|
|||
Mockito.doNothing().when(driverResources).validateDriverJar(any(), anyString());
|
||||
Mockito.when(driverResources.load(any(), anyString(), anyString()))
|
||||
.thenReturn(new DriverResult("", null));
|
||||
Mockito.when(driverResources.loadFromRemote(any()))
|
||||
.thenReturn(new DriverResult("", null));
|
||||
Mockito.when(driverResources.loadFromLocal(any()))
|
||||
.thenReturn(new DriverResult("", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue