support manual upload driver file (#131)
* feat: support upload driver from local * feat: support get origin driver file name * fix: checkstyle * fix: compile error * feat: update docs
This commit is contained in:
parent
38ad685fb7
commit
dc128fc84a
|
@ -15,8 +15,9 @@
|
|||
| demo | demo123 | 系统管理员 |
|
||||
| dev | dev123 | 普通 |
|
||||
|
||||
## 社区
|
||||
|
||||
[点击联系](https://doc.databasir.com/#/?id=联系)
|
||||
[点击加入 Databasir 交流群](https://doc.databasir.com/#/?id=联系)
|
||||
|
||||
## 特性
|
||||
|
||||
|
|
|
@ -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,8 @@ 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
|
||||
# jooq
|
||||
spring.jooq.sql-dialect=mysql
|
||||
# flyway
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1651035498375" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1963" width="64" height="64" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M558.08 472.064c48.128 53.248-13.312 103.424-13.312 103.424s119.808-61.44 65.536-139.264c-51.2-71.68-91.136-107.52 122.88-232.448 0 1.024-335.872 86.016-175.104 268.288" fill="#FF0000" p-id="1964"></path><path d="M610.304 5.12s101.376 101.376-96.256 258.048C356.352 389.12 478.208 460.8 514.048 543.744 420.864 459.776 354.304 386.048 399.36 317.44 463.872 216.064 651.264 166.912 610.304 5.12" fill="#FF0000" p-id="1965"></path><path d="M720.896 757.76c183.296-95.232 98.304-188.416 39.936-175.104-15.36 3.072-21.504 5.12-21.504 5.12s5.12-8.192 16.384-11.264c117.76-40.96 207.872 120.832-37.888 186.368-1.024 0 2.048-3.072 3.072-5.12m-337.92 38.912s-37.888 21.504 26.624 29.696c76.8 8.192 117.76 8.192 202.752-8.192 0 0 23.552 15.36 53.248 26.624-191.488 80.896-433.152-5.12-282.624-48.128m-23.552-106.496s-43.008 31.744 23.552 37.888c82.944 8.192 149.504 10.24 261.12-13.312 0 0 16.384 16.384 40.96 24.576-231.424 68.608-490.496 5.12-325.632-49.152" fill="#6699FF" p-id="1966"></path><path d="M811.008 876.544s27.648 23.552-31.744 40.96c-111.616 34.816-460.8 45.056-558.08 2.048-34.816-15.36 31.744-35.84 51.2-40.96 21.504-5.12 34.816-3.072 34.816-3.072-38.912-28.672-251.904 52.224-107.52 75.776 390.144 62.464 712.704-28.672 611.328-74.752M400.384 578.56s-178.176 43.008-63.488 56.32c49.152 6.144 146.432 5.12 235.52-3.072 73.728-6.144 147.456-19.456 147.456-19.456s-26.624 11.264-45.056 24.576c-181.248 48.128-530.432 26.624-430.08-23.552 88.064-39.936 155.648-34.816 155.648-34.816" fill="#6699FF" p-id="1967"></path><path d="M418.816 1015.808c176.128 11.264 446.464-6.144 453.632-90.112 0 0-13.312 31.744-146.432 56.32-150.528 27.648-336.896 24.576-446.464 6.144 2.048 1.024 24.576 20.48 139.264 27.648" fill="#6699FF" p-id="1968"></path></svg>
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -1 +1 @@
|
|||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>databasir</title><script defer="defer" type="module" src="/js/chunk-vendors.9effab81.js"></script><script defer="defer" type="module" src="/js/app.75e63a52.js"></script><link href="/css/chunk-vendors.81898547.css" rel="stylesheet"><link href="/css/app.15b40a89.css" rel="stylesheet"><script defer="defer" src="/js/chunk-vendors-legacy.fb0c8458.js" nomodule></script><script defer="defer" src="/js/app-legacy.cf3474d2.js" nomodule></script></head><body><noscript><strong>We're sorry but databasir doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>databasir</title><script defer="defer" type="module" src="/js/chunk-vendors.9effab81.js"></script><script defer="defer" type="module" src="/js/app.bc6973d3.js"></script><link href="/css/chunk-vendors.81898547.css" rel="stylesheet"><link href="/css/app.15b40a89.css" rel="stylesheet"><script defer="defer" src="/js/chunk-vendors-legacy.fb0c8458.js" nomodule></script><script defer="defer" src="/js/app-legacy.f8c04b90.js" nomodule></script></head><body><noscript><strong>We're sorry but databasir doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,2 +1,2 @@
|
|||
"use strict";(self["webpackChunkdatabasir"]=self["webpackChunkdatabasir"]||[]).push([[17],{5430:function(e,a,t){t.d(a,{v:function(){return r}});var o=t(3872);const n="/api/v1.0/operation_logs",r=e=>o.Z.get(n,{params:e})},6017:function(e,a,t){t.r(a),t.d(a,{default:function(){return j}});var o=t(6252),n=t(3577);const r={key:0},l=(0,o.Uk)("成功"),u={key:1},i=(0,o.Uk)("失败"),p={key:0},g={key:1},s={key:1},c={key:1},d={key:1};function w(e,a,t,w,m,P){const h=(0,o.up)("el-table-column"),f=(0,o.up)("arrow-down"),j=(0,o.up)("el-icon"),L=(0,o.up)("el-dropdown-item"),k=(0,o.up)("el-dropdown-menu"),v=(0,o.up)("el-dropdown"),b=(0,o.up)("el-tag"),y=(0,o.up)("el-link"),O=(0,o.up)("el-table"),C=(0,o.up)("el-main"),W=(0,o.up)("el-pagination"),_=(0,o.up)("el-footer"),D=(0,o.up)("el-container");return(0,o.wg)(),(0,o.j4)(D,null,{default:(0,o.w5)((()=>[(0,o.Wm)(C,null,{default:(0,o.w5)((()=>[(0,o.Wm)(O,{data:m.projectOperationLogPageData.data},{default:(0,o.w5)((()=>[(0,o.Wm)(h,{prop:"id",label:""}),(0,o.Wm)(h,{prop:"operationModule",label:"系统模块"}),(0,o.Wm)(h,{prop:"operatorNickname",label:"操作人"}),(0,o.Wm)(h,{prop:"operationName",label:"操作"}),(0,o.Wm)(h,{label:"状态"},{header:(0,o.w5)((()=>[(0,o.Wm)(v,null,{dropdown:(0,o.w5)((()=>[(0,o.Wm)(k,null,{default:(0,o.w5)((()=>[((0,o.wg)(!0),(0,o.iD)(o.HY,null,(0,o.Ko)(m.logStatusMap,((e,a)=>((0,o.wg)(),(0,o.j4)(L,{key:a,onClick:a=>P.onLogStatusFilter(e),icon:e.icon},{default:(0,o.w5)((()=>[(0,o.Uk)((0,n.zw)(e.text),1)])),_:2},1032,["onClick","icon"])))),128))])),_:1})])),default:(0,o.w5)((()=>[(0,o._)("span",null,[(0,o.Uk)((0,n.zw)(m.logStatusColumnLabel)+" ",1),(0,o.Wm)(j,null,{default:(0,o.w5)((()=>[(0,o.Wm)(f)])),_:1})])])),_:1})])),default:(0,o.w5)((e=>[e.row.isSuccess?((0,o.wg)(),(0,o.iD)("span",r,[(0,o.Wm)(b,{type:"success"},{default:(0,o.w5)((()=>[l])),_:1})])):((0,o.wg)(),(0,o.iD)("span",u,[(0,o.Wm)(b,{type:"danger"},{default:(0,o.w5)((()=>[i])),_:1})]))])),_:1}),(0,o.Wm)(h,{label:"错误信息"},{default:(0,o.w5)((e=>[e.row.isSuccess?((0,o.wg)(),(0,o.iD)("span",p)):((0,o.wg)(),(0,o.iD)("span",g,(0,n.zw)(e.row.operationResponse.errMessage),1))])),_:1}),(0,o.Wm)(h,{label:"涉及分组"},{default:(0,o.w5)((e=>[e.row.involvedGroup?((0,o.wg)(),(0,o.j4)(y,{key:0},{default:(0,o.w5)((()=>[(0,o.Uk)((0,n.zw)(e.row.involvedGroup.name),1)])),_:2},1024)):((0,o.wg)(),(0,o.iD)("span",s," - "))])),_:1}),(0,o.Wm)(h,{label:"涉及项目"},{default:(0,o.w5)((e=>[e.row.involvedProject?((0,o.wg)(),(0,o.j4)(y,{key:0},{default:(0,o.w5)((()=>[(0,o.Uk)((0,n.zw)(e.row.involvedProject.name),1)])),_:2},1024)):((0,o.wg)(),(0,o.iD)("span",c," - "))])),_:1}),(0,o.Wm)(h,{label:"涉及用户"},{default:(0,o.w5)((e=>[e.row.involvedUser?((0,o.wg)(),(0,o.j4)(y,{key:0},{default:(0,o.w5)((()=>[(0,o.Uk)((0,n.zw)(e.row.involvedUser.nickname),1)])),_:2},1024)):((0,o.wg)(),(0,o.iD)("span",d," - "))])),_:1}),(0,o.Wm)(h,{prop:"createAt",label:"记录时间"})])),_:1},8,["data"])])),_:1}),(0,o.Wm)(_,null,{default:(0,o.w5)((()=>[(0,o.Wm)(W,{layout:"prev, pager, next","hide-on-single-page":!1,currentPage:m.projectOperationLogPageData.number,"page-size":m.projectOperationLogPageData.size,"page-count":m.projectOperationLogPageData.totalPages,onCurrentChange:P.onProjectOperationLogCurrentPageChange},null,8,["currentPage","page-size","page-count","onCurrentChange"])])),_:1})])),_:1})}var m=t(5430),P={data(){return{projectOperationLogPageData:{data:[],number:1,size:10,totalElements:0,totalPages:1},projectOperationLogPageQuery:{page:0,size:10,isSuccess:null,involveProjectId:null,module:null},logStatusColumnLabel:"全部",logStatusMap:[{text:"全部",icon:"List",value:null},{text:"成功",icon:"CircleCheck",value:!0},{text:"失败",icon:"CircleClose",value:!1}]}},created(){this.fetchProjectOperationLogs()},methods:{fetchProjectOperationLogs(e){this.projectOperationLogPageQuery.page=e?e-1:null,(0,m.v)(this.projectOperationLogPageQuery).then((e=>{e.errCode||(this.projectOperationLogPageData.data=e.data.content,this.projectOperationLogPageData.number=e.data.number+1,this.projectOperationLogPageData.size=e.data.size,this.projectOperationLogPageData.totalPages=e.data.totalPages,this.projectOperationLogPageData.totalElements=e.data.totalElements)}))},onProjectOperationLogCurrentPageChange(e){e&&e-1!=this.projectOperationLogPageQuery.page&&(this.projectOperationLogPageQuery.page=e-1,this.fetchProjectOperationLogs(e))},onQuery(){this.fetchProjectOperationLogs()},onLogStatusFilter(e){this.projectOperationLogPageQuery.isSuccess=e.value,null==e.value?this.logStatusColumnLabel="状态":this.logStatusColumnLabel=e.text,this.onQuery()}}},h=t(3744);const f=(0,h.Z)(P,[["render",w]]);var j=f}}]);
|
||||
//# sourceMappingURL=17.177f76a3.js.map
|
||||
//# sourceMappingURL=17.f8914b9e.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -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,28 @@ 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 +73,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 +100,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.tempLoadFromRemote(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 +154,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) {
|
||||
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());
|
||||
if (StringUtils.isNotBlank(type.getJdbcDriverFilePath())) {
|
||||
return driverResources.loadFromLocal(type.getJdbcDriverFilePath()).getDriverFile();
|
||||
}
|
||||
return driverFile;
|
||||
if (StringUtils.isNotBlank(type.getJdbcDriverFileUrl())) {
|
||||
File remoteFile = driverResources.tempLoadFromRemote(type.getJdbcDriverFileUrl()).getDriverFile();
|
||||
driverResources.validateDriverJar(remoteFile, type.getJdbcDriverClassName());
|
||||
String targetFile = driverResources.copyToStandardDirectory(remoteFile, type.getDatabaseType());
|
||||
return Paths.get(targetFile).toFile();
|
||||
}
|
||||
String databaseType = type.getDatabaseType();
|
||||
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception("驱动加载失败, database=" + databaseType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@ package com.databasir.core.infrastructure.driver;
|
|||
import com.databasir.core.domain.DomainErrors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
@ -19,7 +21,7 @@ import java.net.URLClassLoader;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.UUID;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
@Component
|
||||
|
@ -32,48 +34,62 @@ public class DriverResources {
|
|||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
public DriverResult load(String driverFilePath, String driverFileUrl, String databaseType) {
|
||||
if (driverFilePath == null) {
|
||||
String targetFile = targetDriverFile(databaseType);
|
||||
File file = download(driverFileUrl, targetFile);
|
||||
return new DriverResult(targetFile, file);
|
||||
}
|
||||
File driverFile = Paths.get(driverFilePath).toFile();
|
||||
public DriverResult loadFromLocal(String localPath) {
|
||||
File driverFile = Paths.get(localPath).toFile();
|
||||
if (driverFile.exists()) {
|
||||
return new DriverResult(driverFilePath, driverFile);
|
||||
return new DriverResult(localPath, driverFile);
|
||||
} else {
|
||||
String targetFile = targetDriverFile(databaseType);
|
||||
File file = download(driverFileUrl, targetFile);
|
||||
return new DriverResult(targetFile, file);
|
||||
throw DomainErrors.UPLOAD_DRIVER_FILE_ERROR.exception();
|
||||
}
|
||||
}
|
||||
|
||||
private File download(String driverFileUrl, String targetFile) {
|
||||
Path path = Path.of(targetFile);
|
||||
public DriverResult tempLoadFromRemote(String remoteUrl) {
|
||||
Path dirPath;
|
||||
try {
|
||||
dirPath = Files.createTempDirectory("databasir-drivers");
|
||||
} catch (IOException e) {
|
||||
log.error("load driver error cause create temp dir failed", e);
|
||||
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception();
|
||||
}
|
||||
File file = download(remoteUrl, dirPath.toString());
|
||||
return new DriverResult(file.getAbsolutePath(), file);
|
||||
}
|
||||
|
||||
// create parent directory
|
||||
if (Files.notExists(path)) {
|
||||
path.getParent().toFile().mkdirs();
|
||||
try {
|
||||
Files.createFile(path);
|
||||
} catch (IOException e) {
|
||||
log.error("create file error " + targetFile, e);
|
||||
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception(e.getMessage());
|
||||
}
|
||||
private File download(String driverFileUrl, String parentDir) {
|
||||
Path parentDirPath = Paths.get(parentDir);
|
||||
try {
|
||||
Files.createDirectories(parentDirPath);
|
||||
} catch (IOException e) {
|
||||
log.error("下载驱动时创建目录失败", e);
|
||||
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception(e);
|
||||
}
|
||||
|
||||
// download
|
||||
try {
|
||||
return restTemplate.execute(driverFileUrl, HttpMethod.GET, null, response -> {
|
||||
if (response.getStatusCode().is2xxSuccessful()) {
|
||||
File file = path.toFile();
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
String prefix = System.currentTimeMillis() + "";
|
||||
String originFileName = response.getHeaders().getContentDisposition().getFilename();
|
||||
String filename;
|
||||
if (originFileName == null) {
|
||||
URL url = new URL(driverFileUrl);
|
||||
String nameFromUrl = FilenameUtils.getName(url.getPath());
|
||||
if (StringUtils.endsWith(nameFromUrl, ".jar")) {
|
||||
filename = prefix + "-" + nameFromUrl;
|
||||
} else {
|
||||
filename = prefix + ".jar";
|
||||
}
|
||||
} else {
|
||||
filename = prefix + "-" + originFileName;
|
||||
}
|
||||
File targetFile = Paths.get(parentDir, filename).toFile();
|
||||
FileOutputStream out = new FileOutputStream(targetFile);
|
||||
StreamUtils.copy(response.getBody(), out);
|
||||
IOUtils.closeQuietly(out, ex -> log.error("close file error", ex));
|
||||
log.info("{} download success ", targetFile);
|
||||
return file;
|
||||
return targetFile;
|
||||
} else {
|
||||
log.error("{} download error from {}: {} ", targetFile, driverFileUrl, response);
|
||||
log.error("{} download error from {}: {} ", parentDir, driverFileUrl, response);
|
||||
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception("驱动下载失败:"
|
||||
+ response.getStatusCode()
|
||||
+ ", "
|
||||
|
@ -81,7 +97,7 @@ public class DriverResources {
|
|||
}
|
||||
});
|
||||
} catch (RestClientException e) {
|
||||
log.error(targetFile + " download driver error", e);
|
||||
log.error(parentDir + " download driver error", e);
|
||||
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -105,18 +121,26 @@ public class DriverResources {
|
|||
}
|
||||
}
|
||||
|
||||
public String resolveDriverClassName(String driverFileUrl) {
|
||||
String tempFilePath = "temp/" + UUID.randomUUID() + ".jar";
|
||||
File driverFile = download(driverFileUrl, tempFilePath);
|
||||
public String resolveDriverClassNameFromRemote(String driverFileUrl) {
|
||||
DriverResult driverResult = tempLoadFromRemote(driverFileUrl);
|
||||
File driverFile = driverResult.getDriverFile();
|
||||
String className = resolveDriverClassName(driverFile);
|
||||
try {
|
||||
Files.deleteIfExists(driverFile.toPath());
|
||||
} catch (IOException e) {
|
||||
log.error("delete driver error " + tempFilePath, e);
|
||||
log.error("delete driver error from " + driverResult.getDriverFilePath(), e);
|
||||
}
|
||||
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,9 +201,22 @@ public class DriverResources {
|
|||
}
|
||||
}
|
||||
|
||||
private String targetDriverFile(String databaseType) {
|
||||
public String copyToStandardDirectory(File sourceFile, String databaseType) {
|
||||
String targetFile = targetDriverFile(databaseType, sourceFile.getName());
|
||||
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, String fileName) {
|
||||
return driverBaseDirectory
|
||||
+ "/" + databaseType
|
||||
+ "/" + System.currentTimeMillis() + ".jar";
|
||||
+ "/" + fileName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,9 @@ class DatabaseTypeServiceTest extends BaseTest {
|
|||
@BeforeEach
|
||||
public void setUp() {
|
||||
Mockito.doNothing().when(driverResources).validateDriverJar(any(), anyString());
|
||||
Mockito.when(driverResources.load(any(), anyString(), anyString()))
|
||||
Mockito.when(driverResources.tempLoadFromRemote(any()))
|
||||
.thenReturn(new DriverResult("", null));
|
||||
Mockito.when(driverResources.loadFromLocal(any()))
|
||||
.thenReturn(new DriverResult("", null));
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 2c50a58ba5bcbbe28b8e7d76a66589c27454b6dc
|
||||
Subproject commit 6dac399b514868bc6be0209da9c4cbb0f8759ca0
|
Binary file not shown.
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 139 KiB |
Loading…
Reference in New Issue