sql执行器支持库表字段的智能提示

This commit is contained in:
暮光:城中城
2019-08-24 23:13:43 +08:00
parent 6c2141e8b8
commit 607a97b51b
9 changed files with 214 additions and 50 deletions

View File

@@ -85,6 +85,45 @@ public class DatabaseDocController {
return DocDbResponseJson.ok(dataSourceList);
}
/**
* 获取编辑器所需的所有信息,用于自动补全
* @param sourceId
* @return
*/
@PostMapping(value = "/getEditorData")
public ResponseJson getEditorData(Long sourceId) {
// 没权限,返回空
if (!DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE)
&& !DocUserUtil.haveCustomAuth(DbAuthType.VIEW.getName(), DocAuthConst.DB + sourceId)) {
return DocDbResponseJson.ok();
}
BaseMapper baseMapper = this.getBaseMapper(sourceId);
DatabaseFactoryBean databaseFactoryBean = databaseRegistrationBean.getFactoryById(sourceId);
List<DatabaseInfoDto> dbNameDtoList = baseMapper.getDatabaseList();
Map<String, List<TableInfoDto>> dbTableMap = new HashMap<>();
Map<String, List<TableColumnDescDto>> tableColumnsMap = new HashMap<>();
for (DatabaseInfoDto infoDto : dbNameDtoList) {
List<TableInfoDto> dbTableList = baseMapper.getTableList(infoDto.getDbName());
dbTableMap.put(infoDto.getDbName(), dbTableList);
for (TableInfoDto tableInfoDto : dbTableList) {
TableColumnVo tableColumnVo = this.getTableColumnVo(databaseFactoryBean, infoDto.getDbName(), tableInfoDto.getTableName());
// 重新组装一下,只返回两个字段,减少返回数据量
List<TableColumnDescDto> descDtoList = tableColumnVo.getColumnList().stream().map(val -> {
TableColumnDescDto dto = new TableColumnDescDto();
dto.setName(val.getName());
dto.setDescription(val.getDescription());
return dto;
}).collect(Collectors.toList());
tableColumnsMap.put(tableInfoDto.getTableName(), descDtoList);
}
}
Map<String, Object> dbResultMap = new HashMap<>();
dbResultMap.put("db", dbNameDtoList);
dbResultMap.put("table", dbTableMap);
dbResultMap.put("column", tableColumnsMap);
return DocDbResponseJson.ok(dbResultMap);
}
@PostMapping(value = "/getDatabaseList")
public ResponseJson getDatabaseList(Long sourceId) {
BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId);

View File

@@ -40,17 +40,16 @@ public class DatasourceUtil {
dataSource.setConnectionErrorRetryAttempts(2);
dataSource.setBreakAfterAcquireFailure(true);
dataSource.setName("zyplayer-doc-db" + dbDatasource.getId());
DruidPooledConnection tryConnection = dataSource.getConnection(3000);
if (tryConnection == null) {
DruidPooledConnection connection = dataSource.getConnection(3000);
if (connection == null) {
throw new ConfirmException("尝试获取该数据源连接失败:" + dbDatasource.getSourceUrl());
}
tryConnection.recycle();
// 描述连接信息的对象
DatabaseFactoryBean databaseFactoryBean = new DatabaseFactoryBean();
DatabaseMetaData metaData = dataSource.getConnection().getMetaData();
DatabaseMetaData metaData = connection.getMetaData();
String productName = metaData.getDatabaseProductName().toLowerCase();
Resource[] resources = null;
String dbUrl = metaData.getURL();
String dbUrl = dbDatasource.getSourceUrl();
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
if (productName.contains("mysql")) {
// jdbc:mysql://192.168.0.1:3306/user_info?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&autoReconnect=true
@@ -76,6 +75,7 @@ public class DatasourceUtil {
databaseFactoryBean.setDatabaseProduct(DatabaseFactoryBean.DatabaseProduct.SQLSERVER);
resources = resolver.getResources("classpath:com/zyplayer/doc/db/framework/db/mapper/sqlserver/*.xml");
}
connection.recycle();
if (resources == null) {
return null;
}

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(e[i]=c[i]);for(r&&r(t,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=n(n.s=u[l]);return f};var t={},o={2:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var c=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=c;var u=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"872bb020b9d9767172e2",1:"0a0403eb1820498dc9bc"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,u.appendChild(i),c},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);
//# sourceMappingURL=doc-db-manifest.js.map?4e55a966af01f8e2a030
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var a,i,f,l=0,s=[];l<t.length;l++)i=t[l],o[i]&&s.push(o[i][0]),o[i]=0;for(a in c)Object.prototype.hasOwnProperty.call(c,a)&&(e[a]=c[a]);for(r&&r(t,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=n(n.s=u[l]);return f};var t={},o={2:0};n.e=function(e){function r(){a.onerror=a.onload=null,clearTimeout(i);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var c=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=c;var u=document.getElementsByTagName("head")[0],a=document.createElement("script");a.type="text/javascript",a.charset="utf-8",a.async=!0,a.timeout=12e4,n.nc&&a.setAttribute("nonce",n.nc),a.src=n.p+""+e+".js?"+{0:"49668c3fbed15a679eda",1:"0a0403eb1820498dc9bc"}[e];var i=setTimeout(r,12e4);return a.onerror=a.onload=r,u.appendChild(a),c},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);
//# sourceMappingURL=doc-db-manifest.js.map?4cab9b90fde0f8edb725

View File

@@ -8,7 +8,7 @@
<body>
<div id="app"></div>
<script type="text/javascript" src="doc-db-manifest.js?4e55a966af01f8e2a030"></script><script type="text/javascript" src="doc-db-vendor.js?0a0403eb1820498dc9bc"></script><script type="text/javascript" src="doc-db-index.js?872bb020b9d9767172e2"></script></body>
<script type="text/javascript" src="doc-db-manifest.js?4cab9b90fde0f8edb725"></script><script type="text/javascript" src="doc-db-vendor.js?0a0403eb1820498dc9bc"></script><script type="text/javascript" src="doc-db-index.js?49668c3fbed15a679eda"></script></body>
</html>

View File

@@ -4,6 +4,7 @@ var URL = {
getSelfUserInfo: '/user/info/selfInfo',
getUserBaseInfo: '/zyplayer-doc-wiki/common/user/base',
getEditorData: '/zyplayer-doc-db/doc-db/getEditorData',
datasourceList: '/zyplayer-doc-db/doc-db/getDataSourceList',
databaseList: '/zyplayer-doc-db/doc-db/getDatabaseList',
tableList: '/zyplayer-doc-db/doc-db/getTableList',

View File

@@ -1879,7 +1879,18 @@ exports.setCompleters = function(val) {
if (val) completers.push.apply(completers, val);
};
exports.addCompleter = function(completer) {
completers.push(completer);
// zyplayer此处有修改去除由于页面跳转多包含的completer
var newCompleters = [];
for (var i = 0; i < completers.length; i++) {
if (!!completers[i].needDestory) {
continue;
}
newCompleters.push(completers[i]);
}
newCompleters.push(completer);
completers = newCompleters;
// 原生代码:
// completers.push(completer);
};
exports.textCompleter = textCompleter;
exports.keyWordCompleter = keyWordCompleter;

View File

@@ -57,7 +57,11 @@
</div>
</el-dialog>
<!--人员权限弹窗-->
<el-dialog title="权限编辑" :visible.sync="dbSourceAuthDialogVisible" width="900px">
<el-dialog :visible.sync="dbSourceAuthDialogVisible" width="900px" :close-on-click-modal="false">
<span slot="title">
<span>权限编辑</span>
<span style="margin-left: 10px;color: #999;font-size: 12px;"><i class="el-icon-info"></i> 添加删除或编辑之后记得点击保存哦~</span>
</span>
<el-row>
<el-select v-model="dbSourceAuthNewUser" filterable remote reserve-keyword
placeholder="请输入名字、邮箱、账号搜索用户" :remote-method="getSearchUserList"
@@ -119,13 +123,15 @@
methods: {
editDbAuth(row) {
this.newDatasource = JSON.parse(JSON.stringify(row));
app.dbSourceAuthDialogVisible = true;
this.loadDbAuthUserList();
},
loadDbAuthUserList() {
app.dbSourceAuthNewUser = [];
app.dbSourceAuthUserList = [];
app.dbSourceAuthDialogVisible = true;
var param = {sourceId: app.newDatasource.id};
this.common.post(this.apilist1.dbUserAuthList, param, function (json) {
app.dbSourceAuthUserList = json.data || [];
app.dbSourceAuthDialogVisible = true;
});
},
saveUserDbSourceAuth() {

View File

@@ -81,6 +81,9 @@
choiceDatasourceId: "",
databaseList: [],
choiceDatabase: "",
editorDbInfo: [],
editorDbTableInfo: {},
editorColumnInfo: {},
sqlExecuting: false,
executeResultList: [],
@@ -96,9 +99,10 @@
},
mounted: function () {
app = this;
window.tableMetaInfo = "";
app.sqlExecutorEditor = app.initAceEditor("sqlExecutorEditor", 20);
this.loadDatasourceList();
// 下面两行先后顺序不能改
this.addEditorCompleter();
app.sqlExecutorEditor = app.initAceEditor("sqlExecutorEditor", 20);
},
methods: {
initAceEditor(editor, minLines) {
@@ -155,7 +159,7 @@
});
},
inputFavoriteSql(content) {
this.sqlExecutorEditor.setValue(content);
this.sqlExecutorEditor.setValue(content, 1);
this.historyDrawerVisible = false;
},
doExecutorSql() {
@@ -204,10 +208,20 @@
app.datasourceList = json.data || [];
if (app.datasourceList.length > 0) {
app.choiceDatasourceId = app.datasourceList[0].id;
app.loadEditorData();
}
});
},
loadEditorData() {
this.common.post(this.apilist1.getEditorData, {sourceId: this.choiceDatasourceId}, function (json) {
var data = json.data || {};
app.editorDbInfo = data.db || [];
app.editorDbTableInfo = data.table || {};
app.editorColumnInfo = data.column || {};
});
},
datasourceChangeEvents() {
this.loadEditorData();
// this.common.post(this.apilist1.databaseList, {sourceId: this.choiceDatasourceId}, function (json) {
// app.databaseList = json.data || [];
// });
@@ -215,6 +229,99 @@
databaseChangeEvents() {
},
addEditorCompleter() {
var languageTools = ace.require("ace/ext/language_tools");
languageTools.addCompleter({
needDestory: true, // 一定得加上这个参数~不然页面生命周期内页面的切换编辑器会有多个相同的completer
getCompletions: function (editor, session, pos, prefix, callback) {
var isFound = false;
var callbackArr = [];
var lineStr = session.getLine(pos.row).substring(0, pos.column - 1);
if (lineStr.endsWith("from ") || lineStr.endsWith("join ")) {
// 库
for (var i = 0; i < app.editorDbInfo.length; i++) {
callbackArr.push({caption: app.editorDbInfo[i].dbName, snippet: app.editorDbInfo[i].dbName, meta: "database", type: "snippet", score : 1000});
}
// 所有表
for (var key in app.editorDbTableInfo) {
var tableInfo = app.editorDbTableInfo[key];
for (var i = 0; i < tableInfo.length; i++) {
var caption = (!!tableInfo[i].tableComment) ? tableInfo[i].tableName + "-" + tableInfo[i].tableComment : tableInfo[i].tableName;
callbackArr.push({caption: caption, snippet: tableInfo[i].tableName, meta: "table", type: "snippet", score : 1000});
}
}
callback(null, callbackArr);
} else if (lineStr.endsWith(".")) {
// 匹配 库名. 搜索表名
for (var i = 0; i < app.editorDbInfo.length; i++) {
if (lineStr.endsWith(app.editorDbInfo[i].dbName + ".")) {
var tableInfo = app.editorDbTableInfo[app.editorDbInfo[i].dbName];
if (!!tableInfo) {
for (var i = 0; i < tableInfo.length; i++) {
var caption = (!!tableInfo[i].tableComment) ? tableInfo[i].tableName + "-" + tableInfo[i].tableComment : tableInfo[i].tableName;
callbackArr.push({caption: caption, snippet: tableInfo[i].tableName, meta: "table", type: "snippet", score : 1000});
}
isFound = true;
}
}
}
// 未找到,匹配 表名. 搜索字段名
if (!isFound) {
for (var key in app.editorColumnInfo) {
if (!lineStr.endsWith(key + ".")) {
continue;
}
var columnInfo = app.editorColumnInfo[key];
if (!!columnInfo) {
for (var i = 0; i < columnInfo.length; i++) {
var caption = (!!columnInfo[i].description) ? columnInfo[i].name + "-" + columnInfo[i].description : columnInfo[i].name;
callbackArr.push({caption: caption, snippet: columnInfo[i].name, meta: "column", type: "snippet", score : 1000});
}
isFound = true;
}
}
}
callback(null, callbackArr);
} else if (lineStr.endsWith("select ") || lineStr.endsWith("where ") || lineStr.endsWith("and ")) {
var queryText = "";
// 往前加
for (var i = pos.row; i >= 0; i--) {
var tempLine = session.getLine(i);
queryText = tempLine + " " + queryText;
if (tempLine.indexOf(";") >= 0) {
break;
}
}
// 往后加
for (var i = pos.row + 1; i < session.getLength(); i++) {
var tempLine = session.getLine(i);
queryText = queryText + " " + tempLine;
if (tempLine.indexOf(";") >= 0) {
break;
}
}
// 所有表,找下面的字段列表
for (var key in app.editorDbTableInfo) {
var tableInfo = app.editorDbTableInfo[key];
for (var i = 0; i < tableInfo.length; i++) {
if (queryText.indexOf(tableInfo[i].tableName) < 0) {
continue;
}
var columnInfo = app.editorColumnInfo[tableInfo[i].tableName];
if (!!columnInfo) {
for (var i = 0; i < columnInfo.length; i++) {
var caption = (!!columnInfo[i].description) ? columnInfo[i].name + "-" + columnInfo[i].description : columnInfo[i].name;
callbackArr.push({caption: caption, snippet: columnInfo[i].name, meta: "column", type: "snippet", score : 1000});
}
isFound = true;
}
}
}
callback(null, callbackArr);
}
}
});
},
}
}
</script>