Browse Source

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
master
vran 3 years ago
committed by GitHub
parent
commit
dc128fc84a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      README.md
  2. 8
      api/src/main/java/com/databasir/api/DatabaseTypeController.java
  3. 2
      api/src/main/resources/application.properties
  4. 2
      api/src/main/resources/static/css/674.fc5957ed.css
  5. 1
      api/src/main/resources/static/img/jar.a6df0ab2.svg
  6. 2
      api/src/main/resources/static/index.html
  7. 2
      api/src/main/resources/static/js/106-legacy.8a3eaacc.js
  8. 2
      api/src/main/resources/static/js/106-legacy.8a3eaacc.js.map
  9. 2
      api/src/main/resources/static/js/106.3dd0c326.js
  10. 2
      api/src/main/resources/static/js/106.3dd0c326.js.map
  11. 2
      api/src/main/resources/static/js/109-legacy.540e2d81.js
  12. 1
      api/src/main/resources/static/js/109-legacy.540e2d81.js.map
  13. 2
      api/src/main/resources/static/js/109-legacy.e1242421.js
  14. 2
      api/src/main/resources/static/js/109.b545c8be.js
  15. 2
      api/src/main/resources/static/js/109.b545c8be.js.map
  16. 2
      api/src/main/resources/static/js/109.face851d.js
  17. 1
      api/src/main/resources/static/js/109.face851d.js.map
  18. 2
      api/src/main/resources/static/js/17-legacy.5bee094a.js
  19. 2
      api/src/main/resources/static/js/17-legacy.5bee094a.js.map
  20. 2
      api/src/main/resources/static/js/17.f8914b9e.js
  21. 2
      api/src/main/resources/static/js/17.f8914b9e.js.map
  22. 2
      api/src/main/resources/static/js/227-legacy.0a01c860.js
  23. 1
      api/src/main/resources/static/js/227-legacy.0a01c860.js.map
  24. 2
      api/src/main/resources/static/js/227-legacy.25f65528.js
  25. 1
      api/src/main/resources/static/js/227-legacy.25f65528.js.map
  26. 2
      api/src/main/resources/static/js/227.14d3bcfb.js
  27. 1
      api/src/main/resources/static/js/227.14d3bcfb.js.map
  28. 2
      api/src/main/resources/static/js/227.fbdad7cc.js
  29. 1
      api/src/main/resources/static/js/227.fbdad7cc.js.map
  30. 2
      api/src/main/resources/static/js/674-legacy.7c89889f.js
  31. 1
      api/src/main/resources/static/js/674-legacy.7c89889f.js.map
  32. 2
      api/src/main/resources/static/js/674.89830f99.js
  33. 1
      api/src/main/resources/static/js/674.89830f99.js.map
  34. 33
      api/src/main/resources/static/js/707-legacy.1cb0b60a.js
  35. 1
      api/src/main/resources/static/js/707-legacy.1cb0b60a.js.map
  36. 33
      api/src/main/resources/static/js/707-legacy.9397bd6b.js
  37. 1
      api/src/main/resources/static/js/707-legacy.9397bd6b.js.map
  38. 33
      api/src/main/resources/static/js/815.f05e1fa5.js
  39. 1
      api/src/main/resources/static/js/815.f05e1fa5.js.map
  40. 33
      api/src/main/resources/static/js/815.fdde0ea3.js
  41. 1
      api/src/main/resources/static/js/815.fdde0ea3.js.map
  42. 2
      api/src/main/resources/static/js/858-legacy.be953acb.js
  43. 1
      api/src/main/resources/static/js/858-legacy.be953acb.js.map
  44. 2
      api/src/main/resources/static/js/858.f835e841.js
  45. 1
      api/src/main/resources/static/js/858.f835e841.js.map
  46. 4
      api/src/main/resources/static/js/app-legacy.f8c04b90.js
  47. 2
      api/src/main/resources/static/js/app-legacy.f8c04b90.js.map
  48. 4
      api/src/main/resources/static/js/app.bc6973d3.js
  49. 2
      api/src/main/resources/static/js/app.bc6973d3.js.map
  50. 6
      core/src/main/java/com/databasir/core/domain/DomainErrors.java
  51. 4
      core/src/main/java/com/databasir/core/domain/database/converter/DatabaseTypePojoConverter.java
  52. 3
      core/src/main/java/com/databasir/core/domain/database/data/DatabaseTypeCreateRequest.java
  53. 3
      core/src/main/java/com/databasir/core/domain/database/data/DatabaseTypeUpdateRequest.java
  54. 4
      core/src/main/java/com/databasir/core/domain/database/data/DriverClassNameResolveRequest.java
  55. 82
      core/src/main/java/com/databasir/core/domain/database/service/DatabaseTypeService.java
  56. 59
      core/src/main/java/com/databasir/core/domain/database/validator/DatabaseTypeUpdateValidator.java
  57. 22
      core/src/main/java/com/databasir/core/infrastructure/connection/CustomDatabaseConnectionFactory.java
  58. 107
      core/src/main/java/com/databasir/core/infrastructure/driver/DriverResources.java
  59. 4
      core/src/test/java/com/databasir/core/domain/database/service/DatabaseTypeServiceTest.java
  60. 2
      databasir-frontend
  61. BIN
      docs/img/qrcode-group.jpg

3
README.md

@ -15,8 +15,9 @@
| demo | demo123 | 系统管理员 | | demo | demo123 | 系统管理员 |
| dev | dev123 | 普通 | | dev | dev123 | 普通 |
## 社区
[点击联系](https://doc.databasir.com/#/?id=联系) [点击加入 Databasir 交流群](https://doc.databasir.com/#/?id=联系)
## 特性 ## 特性

8
api/src/main/java/com/databasir/api/DatabaseTypeController.java

@ -12,6 +12,7 @@ import org.springframework.data.web.PageableDefault;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List; import java.util.List;
@ -80,4 +81,11 @@ public class DatabaseTypeController {
return JsonData.ok(driverClassName); 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);
}
} }

2
api/src/main/resources/application.properties

@ -4,6 +4,8 @@ spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=${databasir.db.username} spring.datasource.username=${databasir.db.username}
spring.datasource.password=${databasir.db.password} spring.datasource.password=${databasir.db.password}
spring.datasource.url=jdbc:mysql://${databasir.db.url}/${databasir.db.name:databasir} 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 # jooq
spring.jooq.sql-dialect=mysql spring.jooq.sql-dialect=mysql
# flyway # flyway

2
api/src/main/resources/static/css/858.06c68835.css → api/src/main/resources/static/css/674.fc5957ed.css

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/img/jar.a6df0ab2.svg

@ -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

2
api/src/main/resources/static/index.html

@ -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>

2
api/src/main/resources/static/js/106-legacy.77e5209a.js → api/src/main/resources/static/js/106-legacy.8a3eaacc.js

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/106-legacy.77e5209a.js.map → api/src/main/resources/static/js/106-legacy.8a3eaacc.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/106.16ade158.js → api/src/main/resources/static/js/106.3dd0c326.js

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/106.16ade158.js.map → api/src/main/resources/static/js/106.3dd0c326.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/109-legacy.540e2d81.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/109-legacy.540e2d81.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/109-legacy.e1242421.js

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/109.b545c8be.js

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/109-legacy.e1242421.js.map → api/src/main/resources/static/js/109.b545c8be.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/109.face851d.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/109.face851d.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/17-legacy.1c7cf0df.js → api/src/main/resources/static/js/17-legacy.5bee094a.js

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/17-legacy.1c7cf0df.js.map → api/src/main/resources/static/js/17-legacy.5bee094a.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/17.177f76a3.js → api/src/main/resources/static/js/17.f8914b9e.js

@ -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}}]); "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

2
api/src/main/resources/static/js/17.177f76a3.js.map → api/src/main/resources/static/js/17.f8914b9e.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/227-legacy.0a01c860.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/227-legacy.0a01c860.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/227-legacy.25f65528.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/227-legacy.25f65528.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/227.14d3bcfb.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/227.14d3bcfb.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/227.fbdad7cc.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/227.fbdad7cc.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/674-legacy.7c89889f.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/674-legacy.7c89889f.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/674.89830f99.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/674.89830f99.js.map

File diff suppressed because one or more lines are too long

33
api/src/main/resources/static/js/707-legacy.1cb0b60a.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/707-legacy.1cb0b60a.js.map

File diff suppressed because one or more lines are too long

33
api/src/main/resources/static/js/707-legacy.9397bd6b.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/707-legacy.9397bd6b.js.map

File diff suppressed because one or more lines are too long

33
api/src/main/resources/static/js/815.f05e1fa5.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/815.f05e1fa5.js.map

File diff suppressed because one or more lines are too long

33
api/src/main/resources/static/js/815.fdde0ea3.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/815.fdde0ea3.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/858-legacy.be953acb.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/858-legacy.be953acb.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/858.f835e841.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/858.f835e841.js.map

File diff suppressed because one or more lines are too long

4
api/src/main/resources/static/js/app-legacy.cf3474d2.js → api/src/main/resources/static/js/app-legacy.f8c04b90.js

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/app-legacy.cf3474d2.js.map → api/src/main/resources/static/js/app-legacy.f8c04b90.js.map

File diff suppressed because one or more lines are too long

4
api/src/main/resources/static/js/app.75e63a52.js → api/src/main/resources/static/js/app.bc6973d3.js

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/app.75e63a52.js.map → api/src/main/resources/static/js/app.bc6973d3.js.map

File diff suppressed because one or more lines are too long

6
core/src/main/java/com/databasir/core/domain/DomainErrors.java

@ -45,7 +45,11 @@ public enum DomainErrors implements DatabasirErrors {
INVALID_MOCK_DATA_SCRIPT("A_10029", "不合法的表达式"), INVALID_MOCK_DATA_SCRIPT("A_10029", "不合法的表达式"),
CANNOT_DELETE_SELF("A_10030", "无法对自己执行删除账号操作"), CANNOT_DELETE_SELF("A_10030", "无法对自己执行删除账号操作"),
DRIVER_CLASS_NOT_FOUND("A_10031", "获取驱动类名失败"), 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; private final String errCode;

4
core/src/main/java/com/databasir/core/domain/database/converter/DatabaseTypePojoConverter.java

@ -14,10 +14,14 @@ public interface DatabaseTypePojoConverter {
@Mapping(target = "id", ignore = true) @Mapping(target = "id", ignore = true)
@Mapping(target = "updateAt", ignore = true) @Mapping(target = "updateAt", ignore = true)
@Mapping(target = "createAt", ignore = true) @Mapping(target = "createAt", ignore = true)
@Mapping(target = "jdbcDriverFilePath", source = "jdbcDriverFilePath")
DatabaseTypePojo of(DatabaseTypeCreateRequest request, String jdbcDriverFilePath); DatabaseTypePojo of(DatabaseTypeCreateRequest request, String jdbcDriverFilePath);
@Mapping(target = "jdbcDriverFilePath", source = "jdbcDriverFilePath")
DatabaseTypePojo of(DatabaseTypeUpdateRequest request, String jdbcDriverFilePath); DatabaseTypePojo of(DatabaseTypeUpdateRequest request, String jdbcDriverFilePath);
DatabaseTypePojo of(DatabaseTypeUpdateRequest request);
DatabaseTypeDetailResponse toDetailResponse(DatabaseTypePojo data); DatabaseTypeDetailResponse toDetailResponse(DatabaseTypePojo data);
DatabaseTypePageResponse toPageResponse(DatabaseTypePojo pojo, Integer projectCount); DatabaseTypePageResponse toPageResponse(DatabaseTypePojo pojo, Integer projectCount);

3
core/src/main/java/com/databasir/core/domain/database/data/DatabaseTypeCreateRequest.java

@ -15,9 +15,10 @@ public class DatabaseTypeCreateRequest {
@NotBlank @NotBlank
private String description; private String description;
@NotBlank
private String jdbcDriverFileUrl; private String jdbcDriverFileUrl;
private String jdbcDriverFilePath;
@NotBlank @NotBlank
private String jdbcDriverClassName; private String jdbcDriverClassName;

3
core/src/main/java/com/databasir/core/domain/database/data/DatabaseTypeUpdateRequest.java

@ -19,9 +19,10 @@ public class DatabaseTypeUpdateRequest {
@NotBlank @NotBlank
private String description; private String description;
@NotBlank
private String jdbcDriverFileUrl; private String jdbcDriverFileUrl;
private String jdbcDriverFilePath;
@NotBlank @NotBlank
private String jdbcDriverClassName; private String jdbcDriverClassName;

4
core/src/main/java/com/databasir/core/domain/database/data/DriverClassNameResolveRequest.java

@ -2,14 +2,12 @@ package com.databasir.core.domain.database.data;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data @Data
public class DriverClassNameResolveRequest { public class DriverClassNameResolveRequest {
private String databaseType; private String databaseType;
@NotBlank
private String jdbcDriverFileUrl; private String jdbcDriverFileUrl;
private String jdbcDriverFilePath;
} }

82
core/src/main/java/com/databasir/core/domain/database/service/DatabaseTypeService.java

@ -3,6 +3,7 @@ package com.databasir.core.domain.database.service;
import com.databasir.core.domain.DomainErrors; import com.databasir.core.domain.DomainErrors;
import com.databasir.core.domain.database.converter.DatabaseTypePojoConverter; import com.databasir.core.domain.database.converter.DatabaseTypePojoConverter;
import com.databasir.core.domain.database.data.*; 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.connection.DatabaseTypes;
import com.databasir.core.infrastructure.driver.DriverResources; import com.databasir.core.infrastructure.driver.DriverResources;
import com.databasir.core.infrastructure.driver.DriverResult; 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 com.databasir.dao.tables.pojos.DatabaseTypePojo;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
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.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.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -36,14 +42,28 @@ public class DatabaseTypeService {
private final DatabaseTypePojoConverter databaseTypePojoConverter; 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) { 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(); throw DomainErrors.DATABASE_TYPE_NAME_DUPLICATE.exception();
} }
DriverResult result = DriverResult result = loadAndValidate(request.getJdbcDriverFileUrl(),
driverResources.load(null, request.getJdbcDriverFileUrl(), request.getDatabaseType()); request.getJdbcDriverFilePath(), request.getJdbcDriverClassName());
driverResources.validateDriverJar(result.getDriverFile(), request.getJdbcDriverClassName()); String targetPath = driverResources.copyToStandardDirectory(result.getDriverFile(), databaseType);
DatabaseTypePojo pojo = databaseTypePojoConverter.of(request, result.getDriverFilePath()); DatabaseTypePojo pojo = databaseTypePojoConverter.of(request, targetPath);
// TODO workaround
pojo.setJdbcDriverFileUrl(StringUtils.defaultIfBlank(request.getJdbcDriverFileUrl(), ""));
try { try {
return databaseTypeDao.insertAndReturnId(pojo); return databaseTypeDao.insertAndReturnId(pojo);
} catch (DuplicateKeyException e) { } catch (DuplicateKeyException e) {
@ -53,20 +73,23 @@ public class DatabaseTypeService {
@Transactional @Transactional
public void update(DatabaseTypeUpdateRequest request) { public void update(DatabaseTypeUpdateRequest request) {
databaseTypeUpdateValidator.validRequestRequiredParams(request);
databaseTypeDao.selectOptionalById(request.getId()).ifPresent(data -> { databaseTypeDao.selectOptionalById(request.getId()).ifPresent(data -> {
databaseTypeUpdateValidator.validDatabaseTypeIfNecessary(request, data);
String databaseType = request.getDatabaseType();
DatabaseTypePojo pojo; DatabaseTypePojo pojo;
if (!Objects.equals(request.getDatabaseType(), data.getDatabaseType()) if (databaseTypeUpdateValidator.shouldReloadDriver(request, data)) {
|| !Objects.equals(request.getJdbcDriverFileUrl(), data.getJdbcDriverFileUrl())) {
// 名称修改,下载地址修改需要删除原有的 driver 并重新下载验证 // 名称修改,下载地址修改需要删除原有的 driver 并重新下载验证
driverResources.deleteByDatabaseType(data.getDatabaseType()); driverResources.deleteByDatabaseType(data.getDatabaseType());
// download // download
DriverResult result = DriverResult result = loadAndValidate(request.getJdbcDriverFileUrl(),
driverResources.load(null, request.getJdbcDriverFileUrl(), request.getDatabaseType()); request.getJdbcDriverFilePath(), request.getJdbcDriverClassName());
driverResources.validateDriverJar(result.getDriverFile(), request.getJdbcDriverClassName()); String targetPath = driverResources.copyToStandardDirectory(result.getDriverFile(), databaseType);
// validate pojo = databaseTypePojoConverter.of(request, targetPath);
pojo = databaseTypePojoConverter.of(request, result.getDriverFilePath()); pojo.setJdbcDriverFileUrl(StringUtils.defaultIfBlank(request.getJdbcDriverFileUrl(), ""));
} else { } else {
pojo = databaseTypePojoConverter.of(request, data.getJdbcDriverFilePath()); pojo = databaseTypePojoConverter.of(request);
pojo.setJdbcDriverFileUrl(StringUtils.defaultIfBlank(request.getJdbcDriverFileUrl(), ""));
} }
try { 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) { public void deleteById(Integer id) {
databaseTypeDao.selectOptionalById(id).ifPresent(data -> { databaseTypeDao.selectOptionalById(id).ifPresent(data -> {
if (DatabaseTypes.has(data.getDatabaseType())) { if (DatabaseTypes.has(data.getDatabaseType())) {
@ -120,7 +154,25 @@ public class DatabaseTypeService {
} }
public String resolveDriverClassName(DriverClassNameResolveRequest request) { 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();
}
}
} }

59
core/src/main/java/com/databasir/core/domain/database/validator/DatabaseTypeUpdateValidator.java

@ -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;
}
}

22
core/src/main/java/com/databasir/core/infrastructure/connection/CustomDatabaseConnectionFactory.java

@ -1,8 +1,8 @@
package com.databasir.core.infrastructure.connection; package com.databasir.core.infrastructure.connection;
import com.alibaba.excel.util.StringUtils;
import com.databasir.core.domain.DomainErrors; import com.databasir.core.domain.DomainErrors;
import com.databasir.core.infrastructure.driver.DriverResources; import com.databasir.core.infrastructure.driver.DriverResources;
import com.databasir.core.infrastructure.driver.DriverResult;
import com.databasir.dao.impl.DatabaseTypeDao; import com.databasir.dao.impl.DatabaseTypeDao;
import com.databasir.dao.tables.pojos.DatabaseTypePojo; import com.databasir.dao.tables.pojos.DatabaseTypePojo;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -15,10 +15,10 @@ import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.nio.file.Paths;
import java.sql.Connection; import java.sql.Connection;
import java.sql.Driver; import java.sql.Driver;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Objects;
import java.util.Properties; import java.util.Properties;
@Component @Component
@ -83,14 +83,16 @@ public class CustomDatabaseConnectionFactory implements DatabaseConnectionFactor
} }
private File loadDriver(DatabaseTypePojo type) { private File loadDriver(DatabaseTypePojo type) {
String databaseType = type.getDatabaseType(); if (StringUtils.isNotBlank(type.getJdbcDriverFilePath())) {
String file = type.getJdbcDriverFilePath(); return driverResources.loadFromLocal(type.getJdbcDriverFilePath()).getDriverFile();
String url = type.getJdbcDriverFileUrl(); }
DriverResult result = driverResources.load(file, url, databaseType); if (StringUtils.isNotBlank(type.getJdbcDriverFileUrl())) {
File driverFile = result.getDriverFile(); File remoteFile = driverResources.tempLoadFromRemote(type.getJdbcDriverFileUrl()).getDriverFile();
if (!Objects.equals(result.getDriverFilePath(), type.getJdbcDriverFilePath())) { driverResources.validateDriverJar(remoteFile, type.getJdbcDriverClassName());
databaseTypeDao.updateDriverFile(type.getId(), result.getDriverFilePath()); String targetFile = driverResources.copyToStandardDirectory(remoteFile, type.getDatabaseType());
return Paths.get(targetFile).toFile();
} }
return driverFile; String databaseType = type.getDatabaseType();
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception("驱动加载失败, database=" + databaseType);
} }
} }

107
core/src/main/java/com/databasir/core/infrastructure/driver/DriverResources.java

@ -3,8 +3,10 @@ package com.databasir.core.infrastructure.driver;
import com.databasir.core.domain.DomainErrors; import com.databasir.core.domain.DomainErrors;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -19,7 +21,7 @@ import java.net.URLClassLoader;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.UUID; import java.nio.file.StandardCopyOption;
import java.util.jar.JarFile; import java.util.jar.JarFile;
@Component @Component
@ -32,48 +34,62 @@ public class DriverResources {
private final RestTemplate restTemplate; private final RestTemplate restTemplate;
public DriverResult load(String driverFilePath, String driverFileUrl, String databaseType) { public DriverResult loadFromLocal(String localPath) {
if (driverFilePath == null) { File driverFile = Paths.get(localPath).toFile();
String targetFile = targetDriverFile(databaseType);
File file = download(driverFileUrl, targetFile);
return new DriverResult(targetFile, file);
}
File driverFile = Paths.get(driverFilePath).toFile();
if (driverFile.exists()) { if (driverFile.exists()) {
return new DriverResult(driverFilePath, driverFile); return new DriverResult(localPath, driverFile);
} else { } else {
String targetFile = targetDriverFile(databaseType); throw DomainErrors.UPLOAD_DRIVER_FILE_ERROR.exception();
File file = download(driverFileUrl, targetFile);
return new DriverResult(targetFile, file);
} }
} }
private File download(String driverFileUrl, String targetFile) { public DriverResult tempLoadFromRemote(String remoteUrl) {
Path path = Path.of(targetFile); Path dirPath;
try {
// create parent directory dirPath = Files.createTempDirectory("databasir-drivers");
if (Files.notExists(path)) { } catch (IOException e) {
path.getParent().toFile().mkdirs(); log.error("load driver error cause create temp dir failed", e);
try { throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception();
Files.createFile(path); }
} catch (IOException e) { File file = download(remoteUrl, dirPath.toString());
log.error("create file error " + targetFile, e); return new DriverResult(file.getAbsolutePath(), file);
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 // download
try { try {
return restTemplate.execute(driverFileUrl, HttpMethod.GET, null, response -> { return restTemplate.execute(driverFileUrl, HttpMethod.GET, null, response -> {
if (response.getStatusCode().is2xxSuccessful()) { if (response.getStatusCode().is2xxSuccessful()) {
File file = path.toFile(); String prefix = System.currentTimeMillis() + "";
FileOutputStream out = new FileOutputStream(file); 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); StreamUtils.copy(response.getBody(), out);
IOUtils.closeQuietly(out, ex -> log.error("close file error", ex)); IOUtils.closeQuietly(out, ex -> log.error("close file error", ex));
log.info("{} download success ", targetFile); log.info("{} download success ", targetFile);
return file; return targetFile;
} else { } else {
log.error("{} download error from {}: {} ", targetFile, driverFileUrl, response); log.error("{} download error from {}: {} ", parentDir, driverFileUrl, response);
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception("驱动下载失败:" throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception("驱动下载失败:"
+ response.getStatusCode() + response.getStatusCode()
+ ", " + ", "
@ -81,7 +97,7 @@ public class DriverResources {
} }
}); });
} catch (RestClientException e) { } 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()); throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception(e.getMessage());
} }
} }
@ -105,18 +121,26 @@ public class DriverResources {
} }
} }
public String resolveDriverClassName(String driverFileUrl) { public String resolveDriverClassNameFromRemote(String driverFileUrl) {
String tempFilePath = "temp/" + UUID.randomUUID() + ".jar"; DriverResult driverResult = tempLoadFromRemote(driverFileUrl);
File driverFile = download(driverFileUrl, tempFilePath); File driverFile = driverResult.getDriverFile();
String className = resolveDriverClassName(driverFile); String className = resolveDriverClassName(driverFile);
try { try {
Files.deleteIfExists(driverFile.toPath()); Files.deleteIfExists(driverFile.toPath());
} catch (IOException e) { } catch (IOException e) {
log.error("delete driver error " + tempFilePath, e); log.error("delete driver error from " + driverResult.getDriverFilePath(), e);
} }
return className; 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) { public String resolveDriverClassName(File driverFile) {
JarFile jarFile = null; JarFile jarFile = null;
try { 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 return driverBaseDirectory
+ "/" + databaseType + "/" + databaseType
+ "/" + System.currentTimeMillis() + ".jar"; + "/" + fileName;
} }
} }

4
core/src/test/java/com/databasir/core/domain/database/service/DatabaseTypeServiceTest.java

@ -36,7 +36,9 @@ class DatabaseTypeServiceTest extends BaseTest {
@BeforeEach @BeforeEach
public void setUp() { public void setUp() {
Mockito.doNothing().when(driverResources).validateDriverJar(any(), anyString()); 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)); .thenReturn(new DriverResult("", null));
} }

2
databasir-frontend

@ -1 +1 @@
Subproject commit 2c50a58ba5bcbbe28b8e7d76a66589c27454b6dc Subproject commit 6dac399b514868bc6be0209da9c4cbb0f8759ca0

BIN
docs/img/qrcode-group.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 139 KiB

Loading…
Cancel
Save