表数据导出优化,增加表关系图功能

This commit is contained in:
暮光:城中城
2021-06-08 23:04:15 +08:00
parent dcbb2b4ac8
commit 1d5e0e2bf1
42 changed files with 977 additions and 316 deletions

View File

@@ -144,13 +144,6 @@ public class DatabaseDocController {
return DocDbResponseJson.ok(tableColumnVo);
}
@PostMapping(value = "/getTableColumnDescList")
public ResponseJson getTableColumnDescList(Long sourceId, String tableName) {
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
List<TableColumnDescDto> columnDescDto = dbBaseService.getTableColumnDescList(sourceId, tableName);
return DocDbResponseJson.ok(columnDescDto);
}
@PostMapping(value = "/getTableAndColumnBySearch")
public ResponseJson getTableAndColumnBySearch(Long sourceId, String dbName, String searchText) {
if (StringUtils.isBlank(searchText)) {

View File

@@ -1,7 +1,10 @@
package com.zyplayer.doc.db.controller;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.util.TypeUtils;
@@ -9,6 +12,7 @@ import com.zyplayer.doc.core.annotation.AuthMan;
import com.zyplayer.doc.core.exception.ConfirmException;
import com.zyplayer.doc.core.json.ResponseJson;
import com.zyplayer.doc.core.util.StringUtil;
import com.zyplayer.doc.core.util.ZyplayerDocVersion;
import com.zyplayer.doc.data.config.security.DocUserUtil;
import com.zyplayer.doc.data.repository.support.consts.DocAuthConst;
import com.zyplayer.doc.db.controller.param.DataViewParam;
@@ -29,12 +33,14 @@ import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -57,6 +63,9 @@ public class DbDataViewController {
DbBaseFactory dbBaseFactory;
@Resource
BaseDownloadService baseDownloadService;
// 最大允许导出的行数设置的过大有可能会导致内存溢出默认10W条
@Value("${zyplayer.doc.db.download-max-row:100000}")
Integer downloadMaxRow;
@PostMapping(value = "/query")
public ResponseJson query(DataViewParam param) {
@@ -73,13 +82,7 @@ public class DbDataViewController {
if (CollectionUtils.isNotEmpty(executeResult.getResult()) && Objects.equals(param.getPageNum(), 1)) {
responseJson.setTotal((long) executeResult.getResult().size());
if (executeResult.getResult().size() >= param.getPageSize()) {
String queryCountSql = dbBaseService.getQueryCountSql(param);
ExecuteResult countResult = this.query(param.getSourceId(), param.getExecuteId(), executeType, queryCountSql);
if (CollectionUtils.isNotEmpty(countResult.getResult()) && MapUtils.isNotEmpty(countResult.getResult().get(0))) {
Map<String, Object> countMap = countResult.getResult().get(0);
Optional<Object> countAny = countMap.values().stream().findAny();
countAny.ifPresent(count -> responseJson.setTotal(TypeUtils.castToLong(count)));
}
responseJson.setTotal(this.getDataCount(param, executeType));
}
}
return responseJson;
@@ -95,7 +98,11 @@ public class DbDataViewController {
@PostMapping(value = "/download")
public ResponseJson download(HttpServletResponse response, DataViewParam param) {
param.setExecuteId(RandomUtil.simpleUUID());
ExecuteType executeType = this.getExecuteType(param.getSourceId());
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(param.getSourceId());
if (this.getDataCount(param, executeType) > downloadMaxRow) {
return DocDbResponseJson.error(String.format("导出失败,表:%s 数据行数超过最大导出配置 %s请联系管理员修改", param.getTableName(), downloadMaxRow));
}
// 获取列信息等
TableColumnVo tableColumnVo = dbBaseService.getTableColumnList(param.getSourceId(), param.getDbName(), param.getTableName());
Set<String> conditionSet = StringUtils.isBlank(param.getConditionColumn()) ? Collections.emptySet() : Stream.of(param.getConditionColumn().split(",")).collect(Collectors.toSet());
@@ -106,10 +113,8 @@ public class DbDataViewController {
ExecuteParam executeParam = new ExecuteParam();
executeParam.setDatasourceId(param.getSourceId());
executeParam.setExecuteId(param.getExecuteId());
executeParam.setExecuteType(this.getExecuteType(param.getSourceId()));
executeParam.setExecuteType(executeType);
executeParam.setSql(queryAllSql);
// 最大支持10w行数据总得有个上限
executeParam.setMaxRows(100000);
try {
dbBaseService.downloadSingleTableData(response, param, executeParam, columnList, conditionSet);
} catch (Exception e) {
@@ -131,45 +136,85 @@ public class DbDataViewController {
if (StringUtils.isBlank(param.getTableNames())) {
return DocDbResponseJson.warn("请选择导出的表");
}
param.setExecuteId(RandomUtil.simpleUUID());
param.setExecuteId(IdUtil.simpleUUID());
String tempDir = System.getProperty("java.io.tmpdir");
boolean multipleFile = Objects.equals(param.getDownloadFileType(), 2);
boolean isJson = Objects.equals(param.getDownloadType(), "json");
StringBuilder resultSb = new StringBuilder("/*\n" +
" zyplayer-doc 表数据导出\n" +
"\n" +
" 数据库 : " + param.getDbName() + "\n" +
" 数据库类型 : " + dbBaseService.getDatabaseProduct().name() + "\n" +
" 导出时间 : " + DateTime.now().toString() + "\n" +
" 软件版本 : " + ZyplayerDocVersion.version + "\n" +
"*/\n\n");
String[] tableNameArr = param.getTableNames().split(",");
String tempDirName = tempDir + "zyplayer-doc-" + IdUtil.fastSimpleUUID();
try {
for (String tabName : tableNameArr) {
param.setTableName(tabName);
// 先校验总条数是否超过限制
for (String tableName : tableNameArr) {
param.setTableName(tableName);
ExecuteType executeType = this.getExecuteType(param.getSourceId());
if (this.getDataCount(param, executeType) > downloadMaxRow) {
return DocDbResponseJson.error(String.format("导出失败,表:%s 数据行数超过最大导出配置 %s请联系管理员修改", tableName, downloadMaxRow));
}
}
// 创建临时文件夹
FileUtil.mkdir(tempDirName);
// 再分表查数据
String suffix = isJson ? ".json" : ".sql";
for (String tableName : tableNameArr) {
param.setTableName(tableName);
ExecuteType executeType = this.getExecuteType(param.getSourceId());
// 获取列信息等
TableColumnVo tableColumnVo = dbBaseService.getTableColumnList(param.getSourceId(), param.getDbName(), tabName);
TableColumnVo tableColumnVo = dbBaseService.getTableColumnList(param.getSourceId(), param.getDbName(), tableName);
List<TableColumnDescDto> columnList = tableColumnVo.getColumnList();
// 找主键作为更新条件
Set<String> conditionSet = columnList.stream().filter(item -> Objects.equals(item.getIspramary(), "1")).map(TableColumnDescDto::getName).collect(Collectors.toSet());
Set<String> conditionSet = columnList.stream().filter(item -> Objects.equals(item.getPrimaryKey(), "1")).map(TableColumnDescDto::getName).collect(Collectors.toSet());
// 数据查询
String queryAllSql = dbBaseService.getQueryAllSql(param);
ExecuteParam executeParam = new ExecuteParam();
executeParam.setDatasourceId(param.getSourceId());
executeParam.setExecuteId(param.getExecuteId());
executeParam.setExecuteType(this.getExecuteType(param.getSourceId()));
executeParam.setExecuteType(executeType);
executeParam.setSql(queryAllSql);
// 最大支持10w行数据总得有个上限
executeParam.setMaxRows(100000);
String downloadTableData = dbBaseService.getDownloadTableData(param, executeParam, columnList, conditionSet);
resultSb.append(String.format("-- 导出数据表:`%s`.`%s` --\n", param.getDbName(), tabName));
resultSb.append(downloadTableData).append("\n");
// 写入临时文件
if (multipleFile) {
File tempFile = FileUtil.file(tempDirName + "/" + tableName + suffix);
String tableDataSb = isJson ? downloadTableData : String.format("-- 导出数据表:`%s`.`%s` --\n", param.getDbName(), tableName) + downloadTableData;
FileUtil.writeUtf8String(tableDataSb, tempFile);
} else {
resultSb.append(String.format("-- 导出数据表:`%s`.`%s` --\n", param.getDbName(), tableName));
resultSb.append(downloadTableData).append("\n");
}
}
if (multipleFile) {
baseDownloadService.sendResponse(response, param.getDbName(), tempDirName);
} else {
baseDownloadService.sendResponse(response, param.getDbName(), suffix, resultSb.toString());
}
String prefix = Objects.equals(param.getDownloadType(), "json") ? ".json" : ".sql";
baseDownloadService.sendResponse(response, param.getDbName(), prefix, resultSb.toString());
} catch (Exception e) {
e.printStackTrace();
return DocDbResponseJson.error("导出失败:" + e.getMessage());
} finally {
FileUtil.del(tempDirName);
}
return DocDbResponseJson.ok();
}
private Long getDataCount(DataViewParam param, ExecuteType executeType) {
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(param.getSourceId());
String queryCountSql = dbBaseService.getQueryCountSql(param);
ExecuteResult countResult = this.query(param.getSourceId(), param.getExecuteId(), executeType, queryCountSql);
if (CollectionUtils.isNotEmpty(countResult.getResult()) && MapUtils.isNotEmpty(countResult.getResult().get(0))) {
Map<String, Object> countMap = countResult.getResult().get(0);
Optional<Object> countAny = countMap.values().stream().findAny();
return TypeUtils.castToLong(countAny.orElse(0));
}
return 0L;
}
/**
* 执行数据查询
*

View File

@@ -0,0 +1,134 @@
package com.zyplayer.doc.db.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zyplayer.doc.core.annotation.AuthMan;
import com.zyplayer.doc.core.json.ResponseJson;
import com.zyplayer.doc.data.repository.manage.entity.DbTableRelation;
import com.zyplayer.doc.data.repository.manage.param.TableRelationParam;
import com.zyplayer.doc.data.repository.manage.vo.TableRelationVo;
import com.zyplayer.doc.data.service.manage.DbTableRelationService;
import com.zyplayer.doc.db.controller.vo.TableColumnVo;
import com.zyplayer.doc.db.framework.db.dto.TableColumnDescDto;
import com.zyplayer.doc.db.framework.json.DocDbResponseJson;
import com.zyplayer.doc.db.service.DbBaseFactory;
import com.zyplayer.doc.db.service.DbBaseService;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.*;
/**
* 表关系控制器
*
* @author 暮光:城中城
* @since 2021年6月6日
*/
@AuthMan
@RestController
@RequestMapping("/zyplayer-doc-db/table-relation")
public class DbTableRelationController {
private static Logger logger = LoggerFactory.getLogger(DbTableRelationController.class);
@Resource
DbBaseFactory dbBaseFactory;
@Resource
DbTableRelationService dbTableRelationService;
@PostMapping(value = "/update")
public ResponseJson update(TableRelationParam param) {
dbTableRelationService.update(param);
return DocDbResponseJson.ok();
}
@PostMapping(value = "/getRelation")
public ResponseJson getRelation(TableRelationParam param) {
TableRelationVo relationVo = new TableRelationVo();
relationVo.setDbName(param.getDbName());
relationVo.setName(param.getTableName());
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(param.getSourceId());
TableColumnVo tableColumn = dbBaseService.getTableColumnList(param.getSourceId(), param.getDbName(), param.getTableName());
if (CollectionUtils.isNotEmpty(tableColumn.getColumnList())) {
Set<String> drillPath = new HashSet<>();
List<TableRelationVo> childrenRelationList = new LinkedList<>();
for (TableColumnDescDto columnDto : tableColumn.getColumnList()) {
drillPath.add(param.getDbName() + "." + param.getTableName() + "." + columnDto.getName());
TableRelationVo relationVoChildren = new TableRelationVo();
relationVoChildren.setNodeType(1);
relationVoChildren.setDbName(param.getDbName());
relationVoChildren.setTableName(param.getTableName());
relationVoChildren.setName(columnDto.getName());
relationVoChildren.setColumnName(columnDto.getName());
relationVoChildren.setChildren(this.getRelation(param.getSourceId(), param.getDbName(), param.getTableName(), columnDto.getName(), drillPath,1));
childrenRelationList.add(relationVoChildren);
}
relationVo.setChildren(childrenRelationList);
}
return DocDbResponseJson.ok(relationVo);
}
public List<TableRelationVo> getRelation(Long sourceId, String dbName, String tableName, String columnName, Set<String> drillPath, int recursion) {
// 最大支持5层关系链展示
if (recursion >= 5) {
return Collections.emptyList();
}
QueryWrapper<DbTableRelation> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("datasource_id", sourceId);
queryWrapper.and(wrapper -> wrapper.or(or -> or.eq("start_db_name", dbName)
.eq("start_table_name", tableName)
.eq("start_column_name", columnName)
).or(or -> or.eq("end_db_name", dbName)
.eq("end_table_name", tableName)
.eq("end_column_name", columnName)
));
List<TableRelationVo> resultRelationList = new LinkedList<>();
List<DbTableRelation> relationList = dbTableRelationService.list(queryWrapper);
if (CollectionUtils.isEmpty(relationList)) {
return resultRelationList;
}
DbBaseService dbBaseService = dbBaseFactory.getDbBaseService(sourceId);
for (DbTableRelation tableRelation : relationList) {
String endDbName = tableRelation.getStartDbName();
String endTableName = tableRelation.getStartTableName();
String endColumnName = tableRelation.getStartColumnName();
if (Objects.equals(tableRelation.getStartDbName(), dbName)
&& Objects.equals(tableRelation.getStartTableName(), tableName)
&& Objects.equals(tableRelation.getStartColumnName(), columnName)) {
endDbName = tableRelation.getEndDbName();
endTableName = tableRelation.getEndTableName();
endColumnName = tableRelation.getEndColumnName();
}
if (drillPath.contains(endDbName + "." + endTableName + "." + endColumnName)) {
continue;
}
drillPath.add(endDbName + "." + endTableName + "." + endColumnName);
TableRelationVo relationVo = new TableRelationVo();
relationVo.setDbName(endDbName);
relationVo.setTableName(endTableName);
relationVo.setName("表:"+endTableName + "\n列" + endColumnName);
relationVo.setColumnName(endColumnName);
TableColumnVo tableColumn = dbBaseService.getTableColumnList(sourceId, endDbName, endTableName);
if (CollectionUtils.isNotEmpty(tableColumn.getColumnList())) {
List<TableRelationVo> childrenRelationList = new LinkedList<>();
for (TableColumnDescDto columnDto : tableColumn.getColumnList()) {
TableRelationVo relationVoChildren = new TableRelationVo();
relationVoChildren.setNodeType(1);
relationVoChildren.setDbName(endDbName);
relationVoChildren.setTableName(endTableName);
relationVoChildren.setName(columnDto.getName());
relationVoChildren.setColumnName(columnDto.getName());
relationVoChildren.setChildren(this.getRelation(sourceId, endDbName, endTableName, columnDto.getName(), drillPath, recursion + 1));
childrenRelationList.add(relationVoChildren);
}
relationVo.setChildren(childrenRelationList);
}
resultRelationList.add(relationVo);
}
return resultRelationList;
}
}

View File

@@ -17,6 +17,7 @@ public class DataViewParam {
private String conditionColumn;
private Integer dropTableFlag;
private Integer createTableFlag;
private Integer downloadFileType;
public Integer getOffset() {
return ((this.pageNum - 1) * this.pageSize);
@@ -141,4 +142,12 @@ public class DataViewParam {
public void setTableNames(String tableNames) {
this.tableNames = tableNames;
}
public Integer getDownloadFileType() {
return downloadFileType;
}
public void setDownloadFileType(Integer downloadFileType) {
this.downloadFileType = downloadFileType;
}
}

View File

@@ -14,7 +14,7 @@ public class TableColumnDescDto {
@ColumnWidth(15)
@ExcelProperty("是否自增")
private String isidenity;
private String selfIncrement;
@ColumnWidth(20)
@ExcelProperty("类型")
@@ -34,7 +34,7 @@ public class TableColumnDescDto {
@ColumnWidth(10)
@ExcelProperty("主键")
private String ispramary;
private String primaryKey;
@ColumnWidth(80)
@ExcelProperty("注释")
@@ -48,14 +48,6 @@ public class TableColumnDescDto {
this.name = name;
}
public String getIsidenity() {
return isidenity;
}
public void setIsidenity(String isidenity) {
this.isidenity = isidenity;
}
public String getType() {
return type;
}
@@ -80,14 +72,6 @@ public class TableColumnDescDto {
this.length = length;
}
public String getIspramary() {
return ispramary;
}
public void setIspramary(String ispramary) {
this.ispramary = ispramary;
}
public String getDescription() {
return description;
}
@@ -111,4 +95,20 @@ public class TableColumnDescDto {
public void setNumericScale(String numericScale) {
this.numericScale = numericScale;
}
public String getSelfIncrement() {
return selfIncrement;
}
public void setSelfIncrement(String selfIncrement) {
this.selfIncrement = selfIncrement;
}
public String getPrimaryKey() {
return primaryKey;
}
public void setPrimaryKey(String primaryKey) {
this.primaryKey = primaryKey;
}
}

View File

@@ -55,16 +55,6 @@ public interface BaseMapper {
*/
List<TableColumnDescDto> getTableColumnList(@Param("dbName") String dbName, @Param("tableName") String tableName);
/**
* 获取字段注释
*
* @param tableName 表名
* @return 表字段注释
* @author 暮光:城中城
* @since 2018年8月8日
*/
List<TableColumnDescDto> getTableColumnDescList(@Param("tableName") String tableName);
/**
* 模糊搜索表和字段
*

View File

@@ -2,51 +2,8 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zyplayer.doc.db.framework.db.mapper.base.BaseMapper">
<resultMap id="TableColumnDescDtoMap" type="com.zyplayer.doc.db.framework.db.dto.TableColumnDescDto" >
<result column="TABLE_NAME" property="tableName" jdbcType="VARCHAR" />
<result column="NAME" property="name" jdbcType="VARCHAR" />
<result column="ISIDENITY" property="isidenity" jdbcType="VARCHAR" />
<result column="TYPE" property="type" jdbcType="VARCHAR" />
<result column="NULLABLE" property="nullable" jdbcType="VARCHAR" />
<result column="LENGTH" property="length" jdbcType="VARCHAR" />
<result column="NUMERIC_SCALE" property="numericScale" jdbcType="VARCHAR" />
<result column="ISPRAMARY" property="ispramary" jdbcType="VARCHAR" />
<result column="DESCRIPTION" property="description" jdbcType="VARCHAR" />
</resultMap>
<resultMap id="QueryTableColumnDescDtoMap" type="com.zyplayer.doc.db.framework.db.dto.QueryTableColumnDescDto" >
<result column="TABLE_NAME" property="tableName" jdbcType="VARCHAR" />
<result column="COLUMN_NAME" property="columnName" jdbcType="VARCHAR" />
<result column="DESCRIPTION" property="description" jdbcType="VARCHAR" />
</resultMap>
<resultMap id="TableStatusDtoMap" type="com.zyplayer.doc.db.controller.vo.TableStatusVo">
<result column="Name" property="name"/>
<result column="Engine" property="engine"/>
<result column="Version" property="version"/>
<result column="Row_format" property="rowFormat"/>
<result column="Rows" property="rows"/>
<result column="Avg_row_length" property="avgRowLength"/>
<result column="Data_length" property="dataLength"/>
<result column="Max_data_length" property="maxDataLength"/>
<result column="Index_length" property="indexLength"/>
<result column="Data_free" property="dataFree"/>
<result column="Auto_increment" property="autoIncrement"/>
<result column="Create_time" property="createTime"/>
<result column="Update_time" property="updateTime"/>
<result column="Check_time" property="checkTime"/>
<result column="Collation" property="collation"/>
<result column="Checksum" property="checksum"/>
<result column="Create_options" property="createOptions"/>
<result column="Comment" property="comment"/>
</resultMap>
<select id="getDatabaseList" resultType="com.zyplayer.doc.db.framework.db.dto.DatabaseInfoDto">
select TABLE_SCHEMA dbName
from `information_schema`.tables
<!--排除系统库-->
where TABLE_SCHEMA != 'information_schema'
group by TABLE_SCHEMA
select SCHEMA_NAME dbName from `information_schema`.SCHEMATA
</select>
<select id="getTableDdl" resultType="java.util.Map">
@@ -59,27 +16,35 @@
<if test="dbName != null">where table_schema=#{dbName}</if>
</select>
<select id="getTableColumnList" resultMap="TableColumnDescDtoMap">
SELECT table_name as TABLE_NAME,COLUMN_NAME as NAME,column_comment DESCRIPTION,data_type TYPE,
COALESCE(CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION) as `LENGTH`,NUMERIC_SCALE as NUMERIC_SCALE,
if(COLUMN_KEY='PRI','1','0') as ISPRAMARY,
if(is_nullable='YES','1','0') NULLABLE
<select id="getTableColumnList" resultType="com.zyplayer.doc.db.framework.db.dto.TableColumnDescDto">
SELECT table_name as tableName,COLUMN_NAME as name,column_comment description,data_type type,
COALESCE(CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION) as `length`,NUMERIC_SCALE as numericScale,
if(COLUMN_KEY='PRI','1','0') as primaryKey,
if(is_nullable='YES','1','0') nullable
FROM `INFORMATION_SCHEMA`.Columns
WHERE table_schema=#{dbName}
<if test="tableName != null">and table_name=#{tableName}</if>
ORDER BY ordinal_position
</select>
<select id="getTableStatus" resultMap="TableStatusDtoMap">
show table status from `${dbName}` like #{tableName}
<select id="getTableStatus" resultType="com.zyplayer.doc.db.controller.vo.TableStatusVo">
<!-- show table status from `${dbName}` like #{tableName} -->
select TABLE_NAME as name, ENGINE as engine, VERSION as version, ROW_FORMAT as rowFormat,
TABLE_ROWS as `rows`, AVG_ROW_LENGTH as avgRowLength, DATA_LENGTH as dataLength,
MAX_DATA_LENGTH as maxDataLength, INDEX_LENGTH as indexLength, DATA_FREE as dataFree,
AUTO_INCREMENT as autoIncrement, CREATE_TIME as createTime, UPDATE_TIME as updateTime,
CHECK_TIME as checkTime, TABLE_COLLATION as `collation`, CHECKSUM as checksum,
CREATE_OPTIONS as createOptions, TABLE_COMMENT as comment
from `information_schema`.tables
where table_schema=#{dbName} and table_name=#{tableName}
</select>
<select id="getTableColumnDescList" resultMap="TableColumnDescDtoMap">
<select id="getTableColumnDescList" resultType="com.zyplayer.doc.db.framework.db.dto.TableColumnDescDto">
select 1
</select>
<select id="getTableAndColumnBySearch" resultMap="QueryTableColumnDescDtoMap">
SELECT TABLE_NAME, COLUMN_NAME, column_comment DESCRIPTION
<select id="getTableAndColumnBySearch" resultType="com.zyplayer.doc.db.framework.db.dto.QueryTableColumnDescDto">
SELECT TABLE_NAME as tableName, column_name as columnName, column_comment as description
FROM `INFORMATION_SCHEMA`.Columns
WHERE table_schema=#{dbName} AND (COLUMN_NAME like #{searchText} or column_comment like #{searchText})
</select>

View File

@@ -5,11 +5,11 @@
<resultMap id="TableColumnDescDtoMap" type="com.zyplayer.doc.db.framework.db.dto.TableColumnDescDto">
<result column="TABLE_NAME" property="tableName" jdbcType="VARCHAR"/>
<result column="NAME" property="name" jdbcType="VARCHAR"/>
<result column="ISIDENITY" property="isidenity" jdbcType="VARCHAR"/>
<result column="ISIDENITY" property="selfIncrement" jdbcType="VARCHAR"/>
<result column="TYPE" property="type" jdbcType="VARCHAR"/>
<result column="NULLABLE" property="nullable" jdbcType="VARCHAR"/>
<result column="LENGTH" property="length" jdbcType="VARCHAR"/>
<result column="ISPRAMARY" property="ispramary" jdbcType="VARCHAR"/>
<result column="ISPRAMARY" property="primaryKey" jdbcType="VARCHAR"/>
<result column="DESCRIPTION" property="description" jdbcType="VARCHAR"/>
</resultMap>

View File

@@ -4,11 +4,11 @@
<resultMap id="TableColumnDescDtoMap" type="com.zyplayer.doc.db.framework.db.dto.TableColumnDescDto" >
<result column="NAME" property="name" jdbcType="VARCHAR" />
<result column="ISIDENITY" property="isidenity" jdbcType="VARCHAR" />
<result column="ISIDENITY" property="selfIncrement" jdbcType="VARCHAR" />
<result column="TYPE" property="type" jdbcType="VARCHAR" />
<result column="NULLABLE" property="nullable" jdbcType="VARCHAR" />
<result column="LENGTH" property="length" jdbcType="VARCHAR" />
<result column="ISPRAMARY" property="ispramary" jdbcType="VARCHAR" />
<result column="ISPRAMARY" property="primaryKey" jdbcType="VARCHAR" />
<result column="DESCRIPTION" property="description" jdbcType="VARCHAR" />
</resultMap>
@@ -53,14 +53,6 @@
WHERE SYSCOLUMNS.ID = OBJECT_ID(#{tableName})
</select>
<select id="getTableColumnDescList" resultMap="TableColumnDescDtoMap">
SELECT B.name AS NAME,C.value AS DESCRIPTION
FROM sys.tables A
INNER JOIN sys.columns B ON B.object_id = A.object_id
LEFT JOIN sys.extended_properties C ON C.major_id = B.object_id AND C.minor_id = B.column_id
WHERE A.name = #{tableName}
</select>
<select id="getTableAndColumnBySearch" resultMap="QueryTableColumnDescDtoMap">
SELECT top 500
A.name AS TABLE_NAME,B.name AS COLUMN_NAME,C.value AS DESCRIPTION

View File

@@ -1,11 +1,26 @@
package com.zyplayer.doc.db.framework.db.mapper.sqlserver;
import com.zyplayer.doc.db.framework.db.dto.TableColumnDescDto;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* sqlserver数据库的mapper持有对象
*
*
* @author 暮光:城中城
* @since 2018年8月8日
*/
public interface SqlServerMapper {
/**
* 获取字段注释
*
* @param tableName 表名
* @return 表字段注释
* @author 暮光:城中城
* @since 2018年8月8日
*/
List<TableColumnDescDto> getTableColumnDescList(@Param("tableName") String tableName);
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zyplayer.doc.db.framework.db.mapper.base.BaseMapper">
<select id="getTableColumnDescList" resultType="com.zyplayer.doc.db.framework.db.dto.TableColumnDescDto">
SELECT B.name AS name,C.value AS description
FROM sys.tables A
INNER JOIN sys.columns B ON B.object_id = A.object_id
LEFT JOIN sys.extended_properties C ON C.major_id = B.object_id AND C.minor_id = B.column_id
WHERE A.name = #{tableName}
</select>
</mapper>

View File

@@ -6,6 +6,7 @@ import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.zyplayer.doc.core.util.ZyplayerDocVersion;
import com.zyplayer.doc.db.controller.vo.DatabaseExportVo;
import com.zyplayer.doc.db.controller.vo.TableColumnVo;
import com.zyplayer.doc.db.framework.db.dto.TableColumnDescDto;
@@ -47,6 +48,7 @@ public class PoiUtil {
" 数据库 : " + dbName + "\n" +
" 数据库类型 : " + dbType + "\n" +
" 导出时间 : " + DateTime.now().toString() + "\n" +
" 软件版本 : " + ZyplayerDocVersion.version + "\n" +
"*/\n\n");
for (Map.Entry<String, String> entry : ddlSqlMap.entrySet()) {
ddlSqlSb.append("-- ----------------------------\n")
@@ -145,8 +147,8 @@ public class PoiUtil {
// 写入表格
for (TableColumnDescDto dto : tableColumnDescDtos) {
String nullable = Objects.equals(dto.getNullable(), "1") ? "允许" : "不允许";
dataList.add(Arrays.asList(dto.getName(), dto.getIsidenity(), dto.getType(), nullable, dto.getLength(),
dto.getNumericScale(), dto.getIspramary(), dto.getDescription()));
dataList.add(Arrays.asList(dto.getName(), dto.getSelfIncrement(), dto.getType(), nullable, dto.getLength(),
dto.getNumericScale(), dto.getPrimaryKey(), dto.getDescription()));
}
PoiUtil.createTable(document, dataList);
}

View File

@@ -144,19 +144,6 @@ public abstract class DbBaseService {
return tableColumnVo;
}
/**
* 获取字段注释
*
* @param tableName 表名
* @return 表字段注释
* @author 暮光:城中城
* @since 2018年8月8日
*/
public List<TableColumnDescDto> getTableColumnDescList(Long sourceId, String tableName) {
BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId);
return baseMapper.getTableColumnDescList(tableName);
}
/**
* 模糊搜索表和字段
*

View File

@@ -52,11 +52,6 @@ public class HiveServiceImpl extends DbBaseService {
return tableDdlVo;
}
@Override
public List<TableColumnDescDto> getTableColumnDescList(Long sourceId, String tableName) {
throw new ConfirmException("不支持的操作");
}
@Override
public List<QueryTableColumnDescDto> getTableAndColumnBySearch(Long sourceId, String dbName, String searchText) {
throw new ConfirmException("不支持的操作");

View File

@@ -3,7 +3,7 @@ package com.zyplayer.doc.db.service;
import com.zyplayer.doc.db.controller.vo.TableColumnVo;
import com.zyplayer.doc.db.framework.db.dto.TableColumnDescDto;
import com.zyplayer.doc.db.framework.db.enums.DatabaseProductEnum;
import com.zyplayer.doc.db.framework.db.mapper.base.BaseMapper;
import com.zyplayer.doc.db.framework.db.mapper.sqlserver.SqlServerMapper;
import org.springframework.stereotype.Service;
import java.util.List;
@@ -22,8 +22,8 @@ public class SqlserverServiceImpl extends DbBaseService {
public TableColumnVo getTableColumnList(Long sourceId, String dbName, String tableName) {
TableColumnVo tableColumnVo = super.getTableColumnList(sourceId, dbName, tableName);
// SQLSERVER 要单独查字段注释
BaseMapper baseMapper = this.getViewAuthBaseMapper(sourceId);
List<TableColumnDescDto> columnDescList = baseMapper.getTableColumnDescList(tableName);
SqlServerMapper sqlServerMapper = databaseRegistrationBean.getBaseMapper(sourceId, SqlServerMapper.class);
List<TableColumnDescDto> columnDescList = sqlServerMapper.getTableColumnDescList(tableName);
Map<String, TableColumnDescDto> columnMap = tableColumnVo.getColumnList().stream().collect(Collectors.toMap(TableColumnDescDto::getName, val -> val));
// 字段注释
for (TableColumnDescDto descDto : columnDescList) {

View File

@@ -1,7 +1,11 @@
package com.zyplayer.doc.db.service.download;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson.JSONObject;
import com.zyplayer.doc.db.controller.param.DataViewParam;
import com.zyplayer.doc.db.controller.vo.TableDdlVo;
@@ -10,10 +14,13 @@ import com.zyplayer.doc.db.framework.db.mapper.base.ExecuteParam;
import com.zyplayer.doc.db.framework.db.mapper.base.SqlExecutor;
import com.zyplayer.doc.db.service.DbBaseFactory;
import com.zyplayer.doc.db.service.DbBaseService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.net.URLEncoder;
import java.util.List;
import java.util.Objects;
@@ -25,6 +32,7 @@ import java.util.regex.Pattern;
*/
@Service
public class BaseDownloadService {
private static Logger logger = LoggerFactory.getLogger(BaseDownloadService.class);
@Resource
SqlExecutor sqlExecutor;
@@ -141,10 +149,13 @@ public class BaseDownloadService {
}
resultSb.append(resultData);
});
resultSb.append("]");
resultSb.append("]\n");
return resultSb.toString();
}
/**
* 发送字符串到response
*/
public void sendResponse(HttpServletResponse response, String tableName, String prefix, String dataStr) throws Exception {
String fileNameOrigin = tableName + "." + DateTime.now().toString("yyyyMMddHHmmss");
String fileName = URLEncoder.encode(fileNameOrigin, "UTF-8") + prefix;
@@ -154,6 +165,31 @@ public class BaseDownloadService {
IoUtil.write(response.getOutputStream(), "utf-8", true, dataStr);
}
/**
* 把文件夹压缩为zip后发送
*/
public void sendResponse(HttpServletResponse response, String tableName, String tempDirName) throws Exception {
File zipTempFile = File.createTempFile("zyplayer-doc-" + IdUtil.fastSimpleUUID(), ".zip");
ZipUtil.zip(zipTempFile, CharsetUtil.defaultCharset(), false, FileUtil.file(tempDirName));
String fileNameOrigin = tableName + "." + DateTime.now().toString("yyyyMMddHHmmss");
String fileName = URLEncoder.encode(fileNameOrigin, "UTF-8") + ".zip";
response.setContentType("application/octet-stream");
response.setHeader("Content-disposition", "attachment;filename=" + fileName);
response.setCharacterEncoding("utf-8");
try {
IoUtil.write(response.getOutputStream(), true, FileUtil.readBytes(zipTempFile));
} catch (Exception e) {
logger.error("发送数据流失败", e);
} finally {
// 删除临时文件
try {
zipTempFile.delete();
} catch (Exception e) {
logger.error("删除临时ZIP文件失败", e);
}
}
}
/**
* 是否是数值类型
*

View File

@@ -1 +0,0 @@
#app,.el-container,.el-menu{height:100%}.el-header{background-color:#1d4e89!important}.database-list-tree{background-color:#fafafa}.database-list-tree .el-tree-node>.el-tree-node__children{overflow:unset}.el-tree-node__content .el-icon-more{margin-left:5px;color:#606266;font-size:12px;display:none;padding:2px 5px}.el-tree-node__content:hover .el-icon-more{display:inline-block}.login-container{border-radius:5px;-moz-border-radius:5px;background-clip:padding-box;margin:0 auto;width:350px;padding:35px 35px 15px 35px;background:#fff;border:1px solid #eaeaea;-webkit-box-shadow:0 0 25px #cac6c6;box-shadow:0 0 25px #cac6c6}.title{margin:0 auto 40px auto;text-align:center;color:#505458}.remember{margin:0 0 35px 0}.my-info-vue .box-card{margin:10px}.table-info-vue .el-dialog__body{padding:0 20px 10px}.table-info-vue .el-form-item{margin-bottom:5px}.table-info-vue .edit-table-desc{cursor:pointer;color:#409eff}.table-info-vue .description{cursor:pointer;min-height:23px}.table-info-vue .el-table td,.table-info-vue .el-table th{padding:5px 0}.table-info-vue .status-info-row{padding:8px 0}.table-info-vue .status-info-row .label{width:80px;display:inline-block;text-align:right;color:#606266}.table-database-vue .el-table td,.table-database-vue .el-table th{padding:5px 0}.table-database-vue .label{width:140px;text-align:right}.table-database-vue .el-table th,.table-procedure-edit-vue .el-table td,.table-procedure-vue .el-table td{padding:5px 0}body,html{margin:0;padding:0;height:100%}.header-right-user-name{color:#fff;padding-right:5px}.el-menu-vertical{border-right:0}.el-menu-vertical,.el-menu-vertical .el-menu{background:#fafafa}.el-header{background-color:#409eff;color:#333;line-height:40px;text-align:right;height:40px!important}.data-transfer-vue .el-button+.el-button{margin-left:4px}.data-executor-vue .ace-monokai .ace_print-margin{display:none}.data-executor-vue .el-card__body{padding:10px}.data-executor-vue .el-table td,.el-table th{padding:6px 0}.data-executor-vue .execute-result-table .el-input__inner{height:25px;line-height:25px;padding:0 5px}.data-executor-vue .execute-result-table .el-textarea__inner{height:27px;min-height:27px;line-height:25px;padding:0 5px;resize:none}.data-executor-vue .execute-use-time{font-size:12px;margin-right:10px}.data-executor-vue-out .el-tabs__nav-scroll{padding-left:20px}.data-executor-vue-out .el-button+.el-button{margin-left:0}.data-executor-vue-out .el-table__body-wrapper{height:calc(100vh - 180px);overflow-y:auto}

View File

@@ -0,0 +1 @@
#app,.el-container,.el-menu{height:100%}.el-header{background-color:#1d4e89!important}.database-list-tree{background-color:#fafafa}.database-list-tree .el-tree-node>.el-tree-node__children{overflow:unset}.el-tree-node__content .el-icon-more{margin-left:5px;color:#606266;font-size:12px;display:none;padding:2px 5px}.el-tree-node__content:hover .el-icon-more{display:inline-block}.login-container{border-radius:5px;-moz-border-radius:5px;background-clip:padding-box;margin:0 auto;width:350px;padding:35px 35px 15px 35px;background:#fff;border:1px solid #eaeaea;-webkit-box-shadow:0 0 25px #cac6c6;box-shadow:0 0 25px #cac6c6}.title{margin:0 auto 40px auto;text-align:center;color:#505458}.remember{margin:0 0 35px 0}.my-info-vue .box-card{margin:10px}.table-info-vue{padding:0 20px}.table-info-vue .el-dialog__body{padding:0 20px 10px}.table-info-vue .el-form-item{margin-bottom:5px}.table-info-vue .edit-table-desc{cursor:pointer;color:#409eff}.table-info-vue .description{cursor:pointer;min-height:23px}.table-info-vue .el-table td,.table-info-vue .el-table th{padding:5px 0}.table-info-vue .status-info-row{padding:8px 0}.table-info-vue .status-info-row .label{width:80px;display:inline-block;text-align:right;color:#606266}.table-database-vue .el-table td,.table-database-vue .el-table th{padding:5px 0}.table-database-vue .label{width:140px;text-align:right}.table-database-vue .el-table th,.table-procedure-edit-vue .el-table td,.table-procedure-vue .el-table td{padding:5px 0}body,html{margin:0;padding:0;height:100%}.header-right-user-name{color:#fff;padding-right:5px}.el-menu-vertical{border-right:0}.el-menu-vertical,.el-menu-vertical .el-menu{background:#fafafa}.el-header{background-color:#409eff;color:#333;line-height:40px;text-align:right;height:40px!important}.data-executor-vue .ace-monokai .ace_print-margin{display:none}.data-executor-vue .el-card__body{padding:10px}.data-executor-vue .el-table td,.el-table th{padding:6px 0}.data-executor-vue .execute-result-table .el-input__inner{height:25px;line-height:25px;padding:0 5px}.data-executor-vue .execute-result-table .el-textarea__inner{height:27px;min-height:27px;line-height:25px;padding:0 5px;resize:none}.data-executor-vue .execute-use-time{font-size:12px;margin-right:10px}.data-executor-vue-out .el-tabs__nav-scroll{padding-left:20px}.data-executor-vue-out .el-button+.el-button{margin-left:0}.data-executor-vue-out .el-table__body-wrapper{height:calc(100vh - 180px);overflow-y:auto}.data-transfer-vue .el-button+.el-button{margin-left:4px}

View File

@@ -1 +1 @@
<!DOCTYPE html><html lang=en><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-db.png><title>数据库文档管理</title><link href=css/app.b6b9fe42.css rel=preload as=style><link href=css/chunk-vendors.8924efc6.css rel=preload as=style><link href=js/app.3a1822c4.js rel=preload as=script><link href=js/chunk-vendors.d40f789d.js rel=preload as=script><link href=css/chunk-vendors.8924efc6.css rel=stylesheet><link href=css/app.b6b9fe42.css rel=stylesheet></head><body><noscript><strong>We're sorry but zyplayer-db-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=js/chunk-vendors.d40f789d.js></script><script src=js/app.3a1822c4.js></script></body></html>
<!DOCTYPE html><html lang=en><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-db.png><title>数据库文档管理</title><link href=css/app.f232fb4e.css rel=preload as=style><link href=css/chunk-vendors.8924efc6.css rel=preload as=style><link href=js/app.a0ea103c.js rel=preload as=script><link href=js/chunk-vendors.96aa31ea.js rel=preload as=script><link href=css/chunk-vendors.8924efc6.css rel=stylesheet><link href=css/app.f232fb4e.css rel=stylesheet></head><body><noscript><strong>We're sorry but zyplayer-db-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=js/chunk-vendors.96aa31ea.js></script><script src=js/app.a0ea103c.js></script></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