forked from p85126437/datagear
完善数据集表单SQL编辑器功能
This commit is contained in:
parent
77807fba81
commit
7757a6cda4
|
@ -169,7 +169,7 @@ CREATE TABLE DATAGEAR_SQL_DATA_SET_FACTORY
|
|||
DSF_ID VARCHAR(50) NOT NULL,
|
||||
DSF_NAME VARCHAR(100) NOT NULL,
|
||||
DSF_SCHEMA_ID VARCHAR(50) NOT NULL,
|
||||
DSF_SQL VARCHAR(50) NOT NULL,
|
||||
DSF_SQL VARCHAR(1000) NOT NULL,
|
||||
DSF_CREATE_USER_ID VARCHAR(50),
|
||||
DSF_CREATE_TIME TIMESTAMP,
|
||||
PRIMARY KEY (DSF_ID)
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.org. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package org.datagear.web.controller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.datagear.connection.ConnectionSource;
|
||||
import org.datagear.dbinfo.ColumnInfo;
|
||||
import org.datagear.dbinfo.DatabaseInfoResolver;
|
||||
import org.datagear.dbinfo.TableInfo;
|
||||
import org.datagear.management.domain.Schema;
|
||||
import org.datagear.management.domain.User;
|
||||
import org.datagear.management.service.SchemaService;
|
||||
import org.datagear.web.convert.ClassDataConverter;
|
||||
import org.datagear.web.util.KeywordMatcher;
|
||||
import org.datagear.web.util.WebUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
* SQL编辑器控制器。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/sqlEditor")
|
||||
public class SqlEditorController extends AbstractSchemaConnController
|
||||
{
|
||||
@Autowired
|
||||
private DatabaseInfoResolver databaseInfoResolver;
|
||||
|
||||
public SqlEditorController()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public SqlEditorController(MessageSource messageSource, ClassDataConverter classDataConverter,
|
||||
SchemaService schemaService, ConnectionSource connectionSource, DatabaseInfoResolver databaseInfoResolver)
|
||||
{
|
||||
super(messageSource, classDataConverter, schemaService, connectionSource);
|
||||
this.databaseInfoResolver = databaseInfoResolver;
|
||||
}
|
||||
|
||||
public DatabaseInfoResolver getDatabaseInfoResolver()
|
||||
{
|
||||
return databaseInfoResolver;
|
||||
}
|
||||
|
||||
public void setDatabaseInfoResolver(DatabaseInfoResolver databaseInfoResolver)
|
||||
{
|
||||
this.databaseInfoResolver = databaseInfoResolver;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{schemaId}/findTableNames", produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public List<String> findTableNames(HttpServletRequest request, HttpServletResponse response,
|
||||
org.springframework.ui.Model springModel, @PathVariable("schemaId") String schemaId,
|
||||
@RequestParam(value = "keyword", required = false) String keyword) throws Throwable
|
||||
{
|
||||
final User user = WebUtils.getUser(request, response);
|
||||
|
||||
TableInfo[] tableInfos = new ReturnSchemaConnExecutor<TableInfo[]>(request, response, springModel, schemaId,
|
||||
true)
|
||||
{
|
||||
@Override
|
||||
protected TableInfo[] execute(HttpServletRequest request, HttpServletResponse response,
|
||||
org.springframework.ui.Model springModel, Schema schema) throws Throwable
|
||||
{
|
||||
checkReadTableDataPermission(schema, user);
|
||||
|
||||
return getDatabaseInfoResolver().getTableInfos(getConnection());
|
||||
}
|
||||
}.execute();
|
||||
|
||||
List<TableInfo> tableInfoList = SchemaController.findByKeyword(tableInfos, keyword);
|
||||
Collections.sort(tableInfoList, SchemaController.TABLE_INFO_SORT_BY_NAME_COMPARATOR);
|
||||
|
||||
List<String> tableNames = new ArrayList<String>();
|
||||
|
||||
for (TableInfo tableInfo : tableInfoList)
|
||||
tableNames.add(tableInfo.getName());
|
||||
|
||||
return tableNames;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{schemaId}/findColumnNames", produces = CONTENT_TYPE_JSON)
|
||||
@ResponseBody
|
||||
public List<String> findColumnNames(HttpServletRequest request, HttpServletResponse response,
|
||||
org.springframework.ui.Model springModel, @PathVariable("schemaId") String schemaId,
|
||||
@RequestParam("table") final String table,
|
||||
@RequestParam(value = "keyword", required = false) String keyword) throws Throwable
|
||||
{
|
||||
final User user = WebUtils.getUser(request, response);
|
||||
|
||||
ColumnInfo[] columnInfos = new ReturnSchemaConnExecutor<ColumnInfo[]>(request, response, springModel, schemaId,
|
||||
true)
|
||||
{
|
||||
@Override
|
||||
protected ColumnInfo[] execute(HttpServletRequest request, HttpServletResponse response,
|
||||
org.springframework.ui.Model springModel, Schema schema) throws Throwable
|
||||
{
|
||||
checkReadTableDataPermission(schema, user);
|
||||
|
||||
return getDatabaseInfoResolver().getColumnInfos(getConnection(), table);
|
||||
}
|
||||
}.execute();
|
||||
|
||||
List<ColumnInfo> columnInfoList = findByKeyword(columnInfos, keyword);
|
||||
Collections.sort(columnInfoList, COLUMNINFO_INFO_SORT_BY_NAME_COMPARATOR);
|
||||
|
||||
List<String> columnNames = new ArrayList<String>();
|
||||
|
||||
for (ColumnInfo columnInfo : columnInfoList)
|
||||
columnNames.add(columnInfo.getName());
|
||||
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据列名称关键字查询{@linkplain ColumnInfo}列表。
|
||||
*
|
||||
* @param columnInfos
|
||||
* @param columnNameKeyword
|
||||
* @return
|
||||
*/
|
||||
public static List<ColumnInfo> findByKeyword(ColumnInfo[] columnInfos, String columnNameKeyword)
|
||||
{
|
||||
return KeywordMatcher.<ColumnInfo> match(columnInfos, columnNameKeyword,
|
||||
new KeywordMatcher.MatchValue<ColumnInfo>()
|
||||
{
|
||||
@Override
|
||||
public String[] get(ColumnInfo t)
|
||||
{
|
||||
return new String[] { t.getName() };
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Comparator<ColumnInfo> COLUMNINFO_INFO_SORT_BY_NAME_COMPARATOR = new Comparator<ColumnInfo>()
|
||||
{
|
||||
@Override
|
||||
public int compare(ColumnInfo o1, ColumnInfo o2)
|
||||
{
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
};
|
||||
}
|
|
@ -158,6 +158,7 @@ selectonly 是否选择操作,允许为null
|
|||
|
||||
var tableSettings = po.buildDataTableSettingsAjax(tableColumns, po.url("pagingQueryData"));
|
||||
po.initDataTable(tableSettings);
|
||||
po.bindResizeDataTable();
|
||||
})
|
||||
(${pageId});
|
||||
</script>
|
||||
|
|
|
@ -122,6 +122,7 @@ selectonly 是否选择操作,允许为null
|
|||
|
||||
var tableSettings = po.buildDataTableSettingsAjax(tableColumns, po.url("queryData"));
|
||||
po.initDataTable(tableSettings);
|
||||
po.bindResizeDataTable();
|
||||
})
|
||||
(${pageId});
|
||||
</script>
|
||||
|
|
|
@ -166,6 +166,7 @@ selectonly 是否选择操作,允许为null
|
|||
|
||||
var tableSettings = po.buildDataTableSettingsAjax(tableColumns, po.url("pagingQueryData"));
|
||||
po.initDataTable(tableSettings);
|
||||
po.bindResizeDataTable();
|
||||
})
|
||||
(${pageId});
|
||||
</script>
|
||||
|
|
|
@ -44,7 +44,10 @@ readonly 是否只读操作,允许为null
|
|||
<label><@spring.message code='dataSet.sql' /></label>
|
||||
</div>
|
||||
<div class="form-item-value">
|
||||
<textarea name="sql" class="ui-widget ui-widget-content">${(dataSet.sql)!''?html}</textarea>
|
||||
<textarea name="sql" class="ui-widget ui-widget-content" style="display:none;">${(dataSet.sql)!''?html}</textarea>
|
||||
<div class="sql-editor-wrapper ui-widget ui-widget-content">
|
||||
<div id="${pageId}-sql-editor" class="sql-editor"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -59,16 +62,23 @@ readonly 是否只读操作,允许为null
|
|||
</div>
|
||||
<#include "../../include/page_js_obj.ftl" >
|
||||
<#include "../../include/page_obj_form.ftl">
|
||||
<#include "../../include/page_obj_sqlEditor.ftl">
|
||||
<script type="text/javascript">
|
||||
(function(po)
|
||||
{
|
||||
$.initButtons(po.element());
|
||||
po.element(".sql-editor-wrapper").height($(window).height()/5*2);
|
||||
|
||||
po.url = function(action)
|
||||
{
|
||||
return "${contextPath}/analysis/dataSet/" + action;
|
||||
};
|
||||
|
||||
po.getSqlEditorSchemaId = function(){ return po.element("input[name='schemaConnectionFactory.schema.id']").val(); };
|
||||
po.initSqlEditor();
|
||||
var cursor = po.sqlEditor.getCursorPosition();
|
||||
po.sqlEditor.session.insert(cursor, po.element("textarea[name='sql']").val());
|
||||
|
||||
<#if !readonly>
|
||||
po.element(".select-schema-button").click(function()
|
||||
{
|
||||
|
@ -89,13 +99,20 @@ readonly 是否只读操作,允许为null
|
|||
po.open("${contextPath}/schema/select", options);
|
||||
});
|
||||
|
||||
$.validator.addMethod("dataSetSqlRequired", function(value, element)
|
||||
{
|
||||
var sql = po.sqlEditor.getValue();
|
||||
return sql.length > 0;
|
||||
});
|
||||
|
||||
po.form().validate(
|
||||
{
|
||||
ignore : "",
|
||||
rules :
|
||||
{
|
||||
"name" : "required",
|
||||
"schemaConnectionFactory.schema.title" : "required",
|
||||
"sql" : "required",
|
||||
"sql" : "dataSetSqlRequired",
|
||||
},
|
||||
messages :
|
||||
{
|
||||
|
@ -105,6 +122,8 @@ readonly 是否只读操作,允许为null
|
|||
},
|
||||
submitHandler : function(form)
|
||||
{
|
||||
po.element("textarea[name='sql']").val(po.sqlEditor.getValue());
|
||||
|
||||
$(form).ajaxSubmit(
|
||||
{
|
||||
success : function()
|
||||
|
|
|
@ -174,6 +174,7 @@ selectonly 是否选择操作,允许为null
|
|||
|
||||
var tableSettings = po.buildDataTableSettingsAjax(tableColumns, po.url("pagingQueryData"));
|
||||
po.initDataTable(tableSettings);
|
||||
po.bindResizeDataTable();
|
||||
})
|
||||
(${pageId});
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
<#--
|
||||
SQL编辑器JS片段。
|
||||
|
||||
依赖:
|
||||
page_js_obj.ftl
|
||||
|
||||
变量:
|
||||
//数据源ID,不允许为null
|
||||
po.getSqlEditorSchemaId
|
||||
-->
|
||||
<script type="text/javascript">
|
||||
(function(po)
|
||||
{
|
||||
//SQL编辑器,调用po.initSqlEditor()后初始化
|
||||
po.sqlEditor = undefined;
|
||||
|
||||
po.getSqlEditorSchemaId = function(){ return undefined; };
|
||||
|
||||
po.getSqlEditorElementId = function()
|
||||
{
|
||||
return "${pageId}-sql-editor";
|
||||
};
|
||||
|
||||
po.getSqlEditorAutocompleteAjaxOptions = function(autocompleteInfo)
|
||||
{
|
||||
var url = "${contextPath}/sqlEditor/"+po.getSqlEditorSchemaId()+"/";
|
||||
var data = { "keyword" : "" };
|
||||
|
||||
if(autocompleteInfo.type == "table")
|
||||
url += "findTableNames";
|
||||
else if(autocompleteInfo.type == "column")
|
||||
{
|
||||
url += "findColumnNames";
|
||||
data.table = autocompleteInfo.table;
|
||||
}
|
||||
else
|
||||
url += "findUnknownNames";
|
||||
|
||||
return { "url" : url, "data" : data };
|
||||
};
|
||||
|
||||
po.sqlEditorCompleters =
|
||||
[
|
||||
{
|
||||
identifierRegexps : [/[a-zA-Z_0-9\.\$]/],
|
||||
getCompletions: function(editor, session, pos, prefix, callback)
|
||||
{
|
||||
po.getSqlAutocompleteCompletions(editor, session, pos, prefix, callback);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
po.getSqlAutocompleteCompletions = function(editor, session, pos, prefix, callback)
|
||||
{
|
||||
if(!po.getSqlEditorSchemaId())
|
||||
{
|
||||
callback(null, []);
|
||||
return;
|
||||
}
|
||||
|
||||
var info = $.sqlAutocomplete.resolveAutocompleteInfo(editor, session, pos, prefix, ";");
|
||||
|
||||
if(info && info.type == "table" && po.sqlAutocompleteTableCompletions)
|
||||
{
|
||||
callback(null, po.sqlAutocompleteTableCompletions);
|
||||
return;
|
||||
}
|
||||
|
||||
var tableAlias = $.sqlAutocomplete.resolveTableAlias(prefix);
|
||||
|
||||
if(info && info.type == "column" && info.table && po.sqlAutocompleteColumnCompletions)
|
||||
{
|
||||
var columns = po.sqlAutocompleteColumnCompletions[info.table];
|
||||
|
||||
if(columns != null)
|
||||
{
|
||||
var completions = $.sqlAutocomplete.buildCompletions(columns, (tableAlias ? tableAlias+"." : ""));
|
||||
|
||||
callback(null, completions);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(info && (info.type == "table" || (info.type == "column" && info.table)))
|
||||
{
|
||||
var ajaxOptions =
|
||||
{
|
||||
type : "POST",
|
||||
success : function(names)
|
||||
{
|
||||
var completions;
|
||||
|
||||
if(info.type == "table")
|
||||
{
|
||||
completions = $.sqlAutocomplete.buildCompletions(names);
|
||||
po.sqlAutocompleteTableCompletions = completions;
|
||||
}
|
||||
else if(info.type == "column")
|
||||
{
|
||||
completions = $.sqlAutocomplete.buildCompletions(names, (tableAlias ? tableAlias+"." : ""));
|
||||
|
||||
if(!po.sqlAutocompleteColumnCompletions)
|
||||
po.sqlAutocompleteColumnCompletions = {};
|
||||
|
||||
if(names && names.length > 0)
|
||||
po.sqlAutocompleteColumnCompletions[info.table] = names;
|
||||
}
|
||||
|
||||
callback(null, completions);
|
||||
},
|
||||
error : function(){}
|
||||
};
|
||||
|
||||
$.extend(ajaxOptions, po.getSqlEditorAutocompleteAjaxOptions(info));
|
||||
|
||||
$.ajax(ajaxOptions);
|
||||
}
|
||||
else
|
||||
callback(null, []);
|
||||
};
|
||||
|
||||
po.initSqlEditor = function()
|
||||
{
|
||||
var languageTools = ace.require("ace/ext/language_tools");
|
||||
var SqlMode = ace.require("ace/mode/sql").Mode;
|
||||
po.sqlEditor = ace.edit(po.getSqlEditorElementId());
|
||||
po.sqlEditor.session.setMode(new SqlMode());
|
||||
po.sqlEditor.setShowPrintMargin(false);
|
||||
po.sqlEditor.setOptions(
|
||||
{
|
||||
enableBasicAutocompletion: po.sqlEditorCompleters,
|
||||
enableLiveAutocompletion: po.sqlEditorCompleters
|
||||
});
|
||||
|
||||
return po.sqlEditor;
|
||||
};
|
||||
})
|
||||
(${pageId});
|
||||
</script>
|
|
@ -173,6 +173,7 @@ Schema schema 数据库,不允许为null
|
|||
<#include "../include/page_obj_format_time.ftl" >
|
||||
<#include "../include/page_obj_data_permission.ftl">
|
||||
<#include "../include/page_obj_data_permission_ds_table.ftl">
|
||||
<#include "../include/page_obj_sqlEditor.ftl">
|
||||
<script type="text/javascript">
|
||||
(function(po)
|
||||
{
|
||||
|
@ -190,26 +191,8 @@ Schema schema 数据库,不允许为null
|
|||
|
||||
po.cometdInitIfNot();
|
||||
|
||||
po.sqlEditorCompleters =
|
||||
[
|
||||
{
|
||||
identifierRegexps : [/[a-zA-Z_0-9\.\$]/],
|
||||
getCompletions: function(editor, session, pos, prefix, callback)
|
||||
{
|
||||
po.getSqlAutocompleteCompletions(editor, session, pos, prefix, callback);
|
||||
}
|
||||
}
|
||||
];
|
||||
var languageTools = ace.require("ace/ext/language_tools");
|
||||
var SqlMode = ace.require("ace/mode/sql").Mode;
|
||||
po.sqlEditor = ace.edit("${pageId}-sql-editor");
|
||||
po.sqlEditor.session.setMode(new SqlMode());
|
||||
po.sqlEditor.setShowPrintMargin(false);
|
||||
po.sqlEditor.setOptions(
|
||||
{
|
||||
enableBasicAutocompletion: po.sqlEditorCompleters,
|
||||
enableLiveAutocompletion: po.sqlEditorCompleters
|
||||
});
|
||||
po.getSqlEditorSchemaId = function(){ return po.schemaId; };
|
||||
po.initSqlEditor();
|
||||
po.sqlEditor.focus();
|
||||
po.sqlEditor.navigateFileEnd();
|
||||
|
||||
|
@ -283,80 +266,6 @@ Schema schema 数据库,不允许为null
|
|||
}
|
||||
});
|
||||
|
||||
po.getSqlAutocompleteCompletions = function(editor, session, pos, prefix, callback)
|
||||
{
|
||||
var info = $.sqlAutocomplete.resolveAutocompleteInfo(editor, session, pos, prefix, ";");
|
||||
|
||||
if(info && info.type == "table" && po.sqlAutocompleteTableCompletions)
|
||||
{
|
||||
callback(null, po.sqlAutocompleteTableCompletions);
|
||||
return;
|
||||
}
|
||||
|
||||
var tableAlias = $.sqlAutocomplete.resolveTableAlias(prefix);
|
||||
|
||||
if(info && info.type == "column" && info.table && po.sqlAutocompleteColumnCompletions)
|
||||
{
|
||||
var columns = po.sqlAutocompleteColumnCompletions[info.table];
|
||||
|
||||
if(columns != null)
|
||||
{
|
||||
var completions = $.sqlAutocomplete.buildCompletions(columns, (tableAlias ? tableAlias+"." : ""));
|
||||
|
||||
callback(null, completions);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(info && (info.type == "table" || (info.type == "column" && info.table)))
|
||||
{
|
||||
var url = "${contextPath}/sqlpad/"+po.schemaId+"/";
|
||||
var data = { "sqlpadId" : po.sqlpadId, "keyword" : "" };
|
||||
|
||||
if(info.type == "table")
|
||||
url += "findTableNames";
|
||||
else if(info.type == "column")
|
||||
{
|
||||
url += "findColumnNames";
|
||||
data.table = info.table;
|
||||
}
|
||||
else
|
||||
url += "findUnknownNames";
|
||||
|
||||
$.ajax(
|
||||
{
|
||||
type : "POST",
|
||||
url : url,
|
||||
data : data,
|
||||
success : function(names)
|
||||
{
|
||||
var completions;
|
||||
|
||||
if(info.type == "table")
|
||||
{
|
||||
completions = $.sqlAutocomplete.buildCompletions(names);
|
||||
po.sqlAutocompleteTableCompletions = completions;
|
||||
}
|
||||
else if(info.type == "column")
|
||||
{
|
||||
completions = $.sqlAutocomplete.buildCompletions(names, (tableAlias ? tableAlias+"." : ""));
|
||||
|
||||
if(!po.sqlAutocompleteColumnCompletions)
|
||||
po.sqlAutocompleteColumnCompletions = {};
|
||||
|
||||
if(names && names.length > 0)
|
||||
po.sqlAutocompleteColumnCompletions[info.table] = names;
|
||||
}
|
||||
|
||||
callback(null, completions);
|
||||
},
|
||||
error : function(){}
|
||||
});
|
||||
}
|
||||
else
|
||||
callback(null, []);
|
||||
};
|
||||
|
||||
po.getSqlDelimiter = function()
|
||||
{
|
||||
var delimiter = po.element("#sqlDelimiterInput").val();
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
<url-pattern>/globalSetting/*</url-pattern>
|
||||
<url-pattern>/notification/*</url-pattern>
|
||||
<url-pattern>/analysis/*</url-pattern>
|
||||
<url-pattern>/sqlEditor/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
|
|
|
@ -1923,6 +1923,18 @@ table.dataTable tbody tr .column-check .row-data-state .ui-icon{
|
|||
padding-right: 0.5em;
|
||||
}
|
||||
|
||||
|
||||
.page-form-dataSet{}
|
||||
.page-form-dataSet .sql-editor-wrapper{
|
||||
display: inline-block;
|
||||
width: 60%;
|
||||
height: 10em;
|
||||
}
|
||||
.page-form-dataSet .sql-editor-wrapper .sql-editor{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.page-form-chart .chart-plugin-list{
|
||||
margin: 0 0;
|
||||
padding: 0 0;
|
||||
|
|
Loading…
Reference in New Issue