diff --git a/shandan-browser/src/main/java/com/keyware/shandan/browser/controller/SearchController.java b/shandan-browser/src/main/java/com/keyware/shandan/browser/controller/SearchController.java index 2875bd1..c5ea6cc 100644 --- a/shandan-browser/src/main/java/com/keyware/shandan/browser/controller/SearchController.java +++ b/shandan-browser/src/main/java/com/keyware/shandan/browser/controller/SearchController.java @@ -7,16 +7,24 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.keyware.shandan.bianmu.entity.DirectoryResource; import com.keyware.shandan.bianmu.entity.MetadataBasicVo; +import com.keyware.shandan.bianmu.export.DirectoryExport; +import com.keyware.shandan.bianmu.export.ExportCache; +import com.keyware.shandan.bianmu.export.ExportProgress; +import com.keyware.shandan.bianmu.export.MetaTableExport; import com.keyware.shandan.bianmu.service.MetadataService; import com.keyware.shandan.browser.entity.FullSearchParam; import com.keyware.shandan.browser.entity.PageVo; import com.keyware.shandan.browser.entity.SearchConditionVo; -import com.keyware.shandan.browser.service.*; +import com.keyware.shandan.browser.service.FileSearchService; +import com.keyware.shandan.browser.service.MetadataDataService; +import com.keyware.shandan.browser.service.MetadataSearchService; +import com.keyware.shandan.browser.service.SearchService; import com.keyware.shandan.common.entity.Result; import com.keyware.shandan.common.util.FileDownload; import com.keyware.shandan.frame.annotation.AppLog; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; +import org.springframework.util.Assert; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; @@ -24,6 +32,7 @@ import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.List; +import java.util.Map; /** * 组合搜索前端控制器 @@ -202,19 +211,34 @@ public class SearchController { */ @PostMapping("/export/directory/{directoryId}") public Result exportQuery(@PathVariable String directoryId, SearchConditionVo condition, Authentication auth) { + Assert.notNull(auth, "用户信息认证失败"); String userId = auth.getPrincipal().toString(); - ExportComponent export = null; // 这个逻辑只允许同一个用户同时只能有一个导出任务 - if (ExportComponent.getCache(userId) != null) { - export = ExportComponent.getCache(userId).values().stream().findFirst().orElse(null); - } + ExportProgress export = ExportCache.getCache(userId, null); if (export == null) { - export = new ExportComponent(userId); // 查询数据 List list = metadataSearchService.searchAllListByCondition(directoryId, condition); - export.setData(list); - // 打包数据 - export.start(); + export = new DirectoryExport(userId, list); + ExportCache.startExport(export); + } + return Result.of(export.getProgress(), !export.isError()); + } + + @PostMapping("/export/metadata/{metaId}") + public Result exportMetadata(@PathVariable String metaId, SearchConditionVo condition, Authentication auth) { + Assert.notNull(auth, "用户信息认证失败"); + MetadataBasicVo metadata = metadataService.getById(metaId); + Assert.notNull(metadata, "数据资源表不存在"); + + String userId = auth.getPrincipal().toString(); + MetaTableExport export = ExportCache.getCache(userId, null); + if (export == null) { + int count = metadataDataService.count(metadata, condition); + MetaTableExport newExport = new MetaTableExport(userId, metadata); + newExport.queryData((o) -> metadataDataService.queryDataByHandler(metadata, condition, newExport)); + newExport.setDataCount(count); + export = newExport; + ExportCache.startExport(export); } return Result.of(export.getProgress()); @@ -229,11 +253,14 @@ public class SearchController { @GetMapping("/export/status/{exportId}") public Result exportStatus(@PathVariable String exportId, Authentication auth) { String userId = auth.getPrincipal().toString(); - ExportComponent export = ExportComponent.getCache(userId, exportId); + ExportProgress export = ExportCache.getCache(userId, exportId); if (export == null) { return Result.of(null, false, "导出任务不存在"); } - return Result.of(export.getProgress()); + if (export.isError()) { + ExportCache.popCache(userId, exportId); + } + return Result.of(export.getProgress(), !export.isError()); } /** @@ -246,11 +273,11 @@ public class SearchController { @GetMapping("/export/download/{exportId}") public String exportDownload(HttpServletResponse response, @PathVariable String exportId, Authentication auth) { String userId = auth.getPrincipal().toString(); - ExportComponent export = ExportComponent.popCache(userId, exportId); + ExportProgress export = ExportCache.popCache(userId, exportId); if (export == null) { return "错误:导出任务不存在"; } - String path = export.getExportPath() + ".zip"; + String path = export.getDownloadPath(); String downloadName = FileUtil.getName(path); File file = new File(path); return FileDownload.download(response, file, downloadName, true); diff --git a/shandan-browser/src/main/java/com/keyware/shandan/browser/service/MetadataDataService.java b/shandan-browser/src/main/java/com/keyware/shandan/browser/service/MetadataDataService.java index b73d8f8..6d88860 100644 --- a/shandan-browser/src/main/java/com/keyware/shandan/browser/service/MetadataDataService.java +++ b/shandan-browser/src/main/java/com/keyware/shandan/browser/service/MetadataDataService.java @@ -3,6 +3,10 @@ package com.keyware.shandan.browser.service; import com.keyware.shandan.bianmu.entity.MetadataBasicVo; import com.keyware.shandan.browser.entity.PageVo; import com.keyware.shandan.browser.entity.SearchConditionVo; +import org.apache.ibatis.session.ResultHandler; + +import java.util.HashMap; +import java.util.Map; /** * 资源数据服务类 @@ -12,4 +16,8 @@ public interface MetadataDataService { PageVo queryData(MetadataBasicVo metadata, SearchConditionVo condition); String getQuerySql(MetadataBasicVo metadata, SearchConditionVo condition); + + int count(MetadataBasicVo metadata, SearchConditionVo condition); + + void queryDataByHandler(MetadataBasicVo metadata, SearchConditionVo condition, ResultHandler> handler); } diff --git a/shandan-browser/src/main/java/com/keyware/shandan/browser/service/impl/MetadataDataServiceImpl.java b/shandan-browser/src/main/java/com/keyware/shandan/browser/service/impl/MetadataDataServiceImpl.java index f497890..9294a7a 100644 --- a/shandan-browser/src/main/java/com/keyware/shandan/browser/service/impl/MetadataDataServiceImpl.java +++ b/shandan-browser/src/main/java/com/keyware/shandan/browser/service/impl/MetadataDataServiceImpl.java @@ -10,6 +10,7 @@ import com.keyware.shandan.browser.service.MetadataDataService; import com.keyware.shandan.datasource.entity.DataSourceVo; import com.keyware.shandan.datasource.mapper.DynamicDatasourceMapper; import com.keyware.shandan.datasource.service.DataSourceService; +import org.apache.ibatis.session.ResultHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -17,6 +18,8 @@ import java.sql.Blob; import java.sql.Clob; import java.sql.SQLException; import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; /** @@ -56,6 +59,32 @@ public class MetadataDataServiceImpl implements MetadataDataService { return sql; } + public String getCountSql(MetadataBasicVo metadata, SearchConditionVo condition) { + DataSourceVo dataSource = dataSourceService.getById(metadata.getDataSourceId()); + if (dataSource == null) { + throw new RuntimeException("系统没有找到数据源配置"); + } + String sql = MetadataUtils.generateSql(metadata, dataSource, true); + sql += condition.getWhereSql(false); + return sql; + } + + @Override + public int count(MetadataBasicVo metadata, SearchConditionVo condition) { + String sql = getCountSql(metadata,condition); + return dynamicDatasourceMapper.count(sql); + } + + @Override + public void queryDataByHandler(MetadataBasicVo metadata, SearchConditionVo condition, ResultHandler> handler) { + String sql = getQuerySql(metadata, condition); + sql += condition.getOrderBySql(); + dynamicDatasourceMapper.listByHandler(sql, (context) -> { + context.getResultObject().entrySet().forEach(this::convertBigTextField); + handler.handleResult(context); + }); + } + /** * 动态查询分页数据 * @@ -67,18 +96,29 @@ public class MetadataDataServiceImpl implements MetadataDataService { private PageVo dynamicQueryPage(SearchConditionVo condition, String sql) { Page> page = dynamicDatasourceMapper.page(new Page<>(condition.getPage(), condition.getSize()), sql); // 处理Clob类型 - page.setRecords(page.getRecords().stream().peek(data -> data.entrySet().stream().peek(entry -> { - if (entry.getValue() instanceof Clob) { - Clob clob = (Clob) entry.getValue(); - try { - entry.setValue(clob.getSubString(1, (int) clob.length())); - } catch (SQLException ignored) { - entry.setValue("(Clob)"); - } - } else if (entry.getValue() instanceof Blob) { - entry.setValue("(Blob)"); - } - }).collect(Collectors.toSet())).collect(Collectors.toList())); + List> records = page.getRecords() + .stream() + .peek(data -> data.entrySet().forEach(this::convertBigTextField)) + .collect(Collectors.toList()); + page.setRecords(records); return PageVo.pageConvert(page); } + + /** + * 处理Blob和Clob大字段类型 + * + * @param entry + */ + private void convertBigTextField(Map.Entry entry) { + if (entry.getValue() instanceof Clob) { + Clob clob = (Clob) entry.getValue(); + try { + entry.setValue(clob.getSubString(1, (int) clob.length())); + } catch (SQLException ignored) { + entry.setValue("(Clob)"); + } + } else if (entry.getValue() instanceof Blob) { + entry.setValue("(Blob)"); + } + } } diff --git a/shandan-browser/src/main/resources/static/js/browser.js b/shandan-browser/src/main/resources/static/js/browser.js index 6d79b7d..08d04d5 100644 --- a/shandan-browser/src/main/resources/static/js/browser.js +++ b/shandan-browser/src/main/resources/static/js/browser.js @@ -421,47 +421,7 @@ layui.use(['layer', 'listPage', 'globalTree', 'gtable', 'form', 'element', 'drop } function exportDirectory(id, params) { - let layerIndex; - showExportMsgLayer('正在查询需要导出的数据'); - Util.post(`/search/export/directory/${id}`, params, false).then(({flag, data, msg}) => { - if (flag) { - showExportMsgLayer(data.msg); - queryProgress(data.exportId); - } else { - showExportMsgLayer('数据查询失败,' + msg); - } - }) - - function queryProgress(exportId) { - setTimeout(function () { - Util.get(`/search/export/status/${exportId}`, {}, false).then(({flag, data, msg}) => { - if (flag) { - showExportMsgLayer(data.msg); - if (data.isDone) { - layer.close(layerIndex); - parent.window.open(`${ctx}/search/export/download/${exportId}`, '_blank') - } else { - queryProgress(exportId); - } - } else { - showExportMsgLayer('数据查询失败,' + msg); - } - }); - }, 1000); - } - - - function showExportMsgLayer(msg) { - layerIndex && layer.close(layerIndex); - layerIndex = layer.msg(msg, { - icon: 16, - shade: 0.01, - anim: -1, - isOutAnim: false, - time: 1000 * 60 * 30, - closeBtn: 1 - }); - } + Util.exportResource(`/search/export/directory/${id}`, params) } /** diff --git a/shandan-browser/src/main/resources/static/js/meta_search.js b/shandan-browser/src/main/resources/static/js/meta_search.js index b39be93..1f08531 100644 --- a/shandan-browser/src/main/resources/static/js/meta_search.js +++ b/shandan-browser/src/main/resources/static/js/meta_search.js @@ -37,10 +37,14 @@ layui.use(['dropdown', 'gtable', 'laydate', 'form'], function () { limit: 20, toolbar: '#table-title', request: {pageName: 'page', limitName: 'size'}, - defaultToolbar: ['filter', 'print', 'exports', { + defaultToolbar: ['filter', { + title: '导出数据', + layEvent: 'exports', + icon: 'layui-icon-export' + }, { title: '统计报表', layEvent: 'tong-ji', - icon: 'layui-icon-chart' //图标类名 + icon: 'layui-icon-chart' }] }) // 排序事件回调 @@ -53,8 +57,10 @@ layui.use(['dropdown', 'gtable', 'laydate', 'form'], function () { }); // 统计报表自定义 result_table.on('toolbar', function ({event}) { - if (event == 'tong-ji') { + if (event === 'tong-ji') { openStatisticalReport() + }else if(event === 'exports'){ + Util.exportResource(`/search/export/metadata/${metadata.id}`, where); } }); }); diff --git a/shandan-common/src/main/resources/static/js/common/common.js b/shandan-common/src/main/resources/static/js/common/common.js index 9bf7ec9..ff10c92 100644 --- a/shandan-common/src/main/resources/static/js/common/common.js +++ b/shandan-common/src/main/resources/static/js/common/common.js @@ -546,6 +546,49 @@ commonUtil = { return Math.round(size * 100) / 100 + initUnit; } }, + exportResource: (url, params)=>{ + let layerIndex; + showExportMsgLayer('开始准备数据'); + Util.post(url, params, false).then(({flag, data, msg}) => { + if (flag) { + showExportMsgLayer(data.msg); + queryProgress(data.exportId); + } else { + showExportMsgLayer('数据查询失败,' + msg); + } + }) + + function queryProgress(exportId) { + setTimeout(function () { + Util.get(`/search/export/status/${exportId}`, {}, false).then(({flag, data, msg}) => { + if (flag) { + showExportMsgLayer(data.msg); + if (data.isDone) { + layer.close(layerIndex); + parent.window.open(`${ctx}/search/export/download/${exportId}`, '_blank') + } else { + queryProgress(exportId); + } + } else { + showExportMsgLayer('数据查询失败,' + msg); + } + }); + }, 1000); + } + + + function showExportMsgLayer(msg) { + layerIndex && layer.close(layerIndex); + layerIndex = layer.msg(msg, { + icon: 16, + shade: 0.01, + anim: -1, + isOutAnim: false, + time: 1000 * 60 * 30, + closeBtn: 1 + }); + } + } }; const Util = commonUtil; diff --git a/shandan-browser/src/main/java/com/keyware/shandan/browser/service/ExportComponent.java b/shandan-system/src/main/java/com/keyware/shandan/bianmu/export/DirectoryExport.java similarity index 58% rename from shandan-browser/src/main/java/com/keyware/shandan/browser/service/ExportComponent.java rename to shandan-system/src/main/java/com/keyware/shandan/bianmu/export/DirectoryExport.java index e63f45c..ee5d251 100644 --- a/shandan-browser/src/main/java/com/keyware/shandan/browser/service/ExportComponent.java +++ b/shandan-system/src/main/java/com/keyware/shandan/bianmu/export/DirectoryExport.java @@ -1,4 +1,4 @@ -package com.keyware.shandan.browser.service; +package com.keyware.shandan.bianmu.export; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; @@ -14,99 +14,54 @@ import com.keyware.shandan.bianmu.entity.MetadataBasicVo; import com.keyware.shandan.bianmu.service.MetadataService; import com.keyware.shandan.common.util.StreamUtil; import com.keyware.shandan.common.util.StringUtils; -import com.keyware.shandan.common.util.UUIDUtil; import com.keyware.shandan.frame.config.component.AppContext; -import com.keyware.shandan.frame.properties.CustomProperties; import com.keyware.shandan.system.entity.SysFile; import com.keyware.shandan.system.service.SysFileService; import com.keyware.shandan.system.utils.SysSettingUtil; -import lombok.Data; -import lombok.Getter; import java.io.File; -import java.io.Serializable; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; -public class ExportComponent extends Thread { - @Getter - private final String exportId = UUIDUtil.getUUID(); - private final String fileName; - private List dataList; - private final CustomProperties customProperties; +public class DirectoryExport extends ExportProgress { + private final List dataList; private final SysFileService fileService; private final MetadataService metadataService; + private final String outputDir = "目录导出_" + DateUtil.format(new Date(), "yyyyMMddHHmmss"); + private final String outputPath = tempDir + File.separator + outputDir; + private final String zipName = outputPath + ".zip"; - @Getter - private final Progress progress; - - private final static ConcurrentHashMap> cache = new ConcurrentHashMap<>(); - - public ExportComponent(String userId) { - this.customProperties = AppContext.getContext().getBean(CustomProperties.class); + public DirectoryExport(String userId, List dataList) { + super(userId); + this.dataList = dataList; this.fileService = AppContext.getContext().getBean(SysFileService.class); this.metadataService = AppContext.getContext().getBean(MetadataService.class); - fileName = "目录导出_" + DateUtil.format(new Date(), "yyyyMMddHHmmss"); - this.progress = new Progress(this.exportId); - setCache(userId); - } - - public void setCache(String userId) { - Map userCache = cache.get(userId); - if (userCache == null) { - userCache = new HashMap<>(); - } - userCache.put(this.exportId, this); - cache.put(userId, userCache); - } - - static public Map getCache(String userId) { - return cache.get(userId); - } - - static public ExportComponent getCache(String userId, String exportId) { - Map userCache = getCache(userId); - if (userCache == null) { - return null; - } else { - return userCache.get(exportId); - } } - public static ExportComponent popCache(String userId, String exportId) { - Map userCache = getCache(userId); - if (userCache == null) { - return null; - } else { - return userCache.remove(exportId); - } - } - - /** - * 开始打包 - */ @Override public void run() { - String path = getExportPath(); try { - this.progress.setTitle("正在生成临时数据文件"); + this.setTitle("正在生成临时数据文件"); dataList.forEach(resource -> { if ("file".equals(resource.getResourceType())) { exportFile(resource); } else { exportMetadata(resource); } - this.progress.offsetIncrease(); + this.autoAddStep(); }); - this.progress.setTitle("正在打包数据文件"); - ZipUtil.zip(path, path + ".zip", true); - this.progress.setTitle("数据包准备完毕,开始下载"); - this.progress.offsetIncrease(); + this.setTitle("正在打包数据文件"); + ZipUtil.zip(outputPath, zipName, true); + this.autoAddStep(); + this.setDone(); + this.setTitle("数据包准备完毕,开始下载"); } catch (Exception e) { throw new RuntimeException("导出数据在打包时出错", e); } finally { - delete(path); + delete(outputPath); } } @@ -149,7 +104,6 @@ public class ExportComponent extends Thread { } catch (Exception e) { colsArray = new JSONArray(); JSONObject defaultJson = new JSONObject(); - // defaultJson.put("columnName", ""); defaultJson.put("comment", "数据查询失败,无法连接到指定的数据库"); colsArray.add(defaultJson); datas = new ArrayList<>(); @@ -197,21 +151,6 @@ public class ExportComponent extends Thread { writer.close(); } - /** - * 设置需要导出的数据 - * - * @param dataList 数据 - */ - public void setData(List dataList) { - this.dataList = dataList; - this.progress.setFileTotal(dataList.size()); - this.progress.offsetIncrease(); - } - - public String getExportPath() { - return customProperties.getFileStorage().getTempPath() + "/" + fileName; - } - /** * 根据资源路径创建目录 * @@ -219,7 +158,7 @@ public class ExportComponent extends Thread { * @return 资源的的绝对路径 */ private String createResourceDir(String resourcePath) { - String path = getExportPath() + "/" + resourcePath; + String path = outputPath + File.separator + resourcePath; File file = new File(path); File parent = file.getParentFile(); if (!parent.exists()) { @@ -235,49 +174,13 @@ public class ExportComponent extends Thread { } } - @Data - static class Progress implements Serializable { - - private String exportId; - private String title; - private Integer fileTotal; - private Integer offset = 0; - - public Progress(String exportId) { - this.exportId = exportId; - this.title = "正在查询需要导出的数据"; - } - - public void setFileTotal(Integer fileTotal) { - // 加2是因为需要增加一个查询步骤和一个打包的步骤 - this.fileTotal = fileTotal + 2; - } - - public void offsetIncrease() { - this.offset++; - } - - /** - * 获取百分比 - * - * @return - */ - public int getPercentage() { - return Math.round(offset / Float.valueOf(fileTotal) * 100); - } - - /** - * 判断是否完成 - * - * @return - */ - public boolean getIsDone() { - return Objects.equals(offset, fileTotal); - } + @Override + public long getStepTotal() { + return dataList.size() + 1; + } - public String getMsg() { - return "(" + getPercentage() + "%) " + this.title; - } + @Override + public String getDownloadPath() { + return zipName; } } - diff --git a/shandan-system/src/main/java/com/keyware/shandan/bianmu/export/ExportCache.java b/shandan-system/src/main/java/com/keyware/shandan/bianmu/export/ExportCache.java new file mode 100644 index 0000000..3e00327 --- /dev/null +++ b/shandan-system/src/main/java/com/keyware/shandan/bianmu/export/ExportCache.java @@ -0,0 +1,47 @@ +package com.keyware.shandan.bianmu.export; + +import com.keyware.shandan.common.util.StringUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +public class ExportCache { + private final static ConcurrentHashMap> cache = new ConcurrentHashMap<>(); + + public static void startExport(ExportProgress progress) { + Map userCache = cache.get(progress.getUserId()); + if (userCache == null) { + userCache = new HashMap<>(); + } + userCache.put(progress.getExportId(), progress); + cache.put(progress.getUserId(), userCache); + new Thread(progress).start(); + } + + public static T getCache(String userId, String exportId) { + Map userCache = cache.get(userId); + if (userCache == null) { + return null; + } + if (StringUtils.hasText(exportId)) { + return (T) userCache.get(exportId); + } + Optional optional = userCache.values().stream().findFirst(); + if (optional.isPresent()) { + return (T) optional.get(); + } + return null; + } + + public static T popCache(String userId, String exportId) { + Map userCache = cache.get(userId); + if (userCache == null) { + return null; + } else { + ExportProgress progress = userCache.remove(exportId); + return (T) progress; + } + } +} diff --git a/shandan-system/src/main/java/com/keyware/shandan/bianmu/export/ExportProgress.java b/shandan-system/src/main/java/com/keyware/shandan/bianmu/export/ExportProgress.java new file mode 100644 index 0000000..f073285 --- /dev/null +++ b/shandan-system/src/main/java/com/keyware/shandan/bianmu/export/ExportProgress.java @@ -0,0 +1,90 @@ +package com.keyware.shandan.bianmu.export; + +import cn.hutool.core.io.FileUtil; +import com.keyware.shandan.common.util.UUIDUtil; +import com.keyware.shandan.frame.config.component.AppContext; +import com.keyware.shandan.frame.properties.CustomProperties; +import lombok.Data; + +import java.io.File; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +@Data +public abstract class ExportProgress implements Runnable, Serializable { + + private String exportId = UUIDUtil.getUUID(); + private String userId; + private String title; + private Integer currentStep = 0; + protected final String tempDir; + + protected boolean error = false; + + public ExportProgress(String userId) { + this.userId = userId; + this.title = "正在查询需要导出的数据"; + CustomProperties customProperties = AppContext.getContext().getBean(CustomProperties.class); + tempDir = customProperties.getFileStorage().getTempPath(); + } + + public abstract void run(); + + /** + * 进度总步数 + */ + public abstract long getStepTotal(); + + public abstract String getDownloadPath(); + + /** + * 偏移量自增 + */ + public void autoAddStep() { + this.currentStep++; + } + + /** + * 获取百分比 + * + * @return + */ + public int getPercentage() { + return Math.round(currentStep / (float) getStepTotal() * 100); + } + + /** + * 判断是否完成 + * + * @return + */ + public boolean getIsDone() { + return currentStep == getStepTotal(); + } + + protected void setDone() { + currentStep = getCurrentStep(); + } + + public String getMsg() { + return "(" + getPercentage() + "%) " + this.title; + } + + public Map getProgress() { + Map map = new HashMap<>(); + map.put("exportId", exportId); + map.put("title", title); + map.put("msg", getMsg()); + map.put("isDone", getIsDone()); + map.put("isError", error); + return map; + } + + public void clean() { + File file = new File(getDownloadPath()); + if (file.exists()) { + FileUtil.del(file); + } + } +} \ No newline at end of file diff --git a/shandan-system/src/main/java/com/keyware/shandan/bianmu/export/MetaTableExport.java b/shandan-system/src/main/java/com/keyware/shandan/bianmu/export/MetaTableExport.java new file mode 100644 index 0000000..1d19e30 --- /dev/null +++ b/shandan-system/src/main/java/com/keyware/shandan/bianmu/export/MetaTableExport.java @@ -0,0 +1,119 @@ +package com.keyware.shandan.bianmu.export; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.poi.excel.BigExcelWriter; +import cn.hutool.poi.excel.ExcelUtil; +import cn.hutool.poi.excel.ExcelWriter; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.keyware.shandan.bianmu.entity.MetadataBasicVo; +import com.keyware.shandan.bianmu.service.MetadataService; +import com.keyware.shandan.common.util.StreamUtil; +import com.keyware.shandan.common.util.StringUtils; +import com.keyware.shandan.frame.config.component.AppContext; +import org.apache.ibatis.session.ResultContext; +import org.apache.ibatis.session.ResultHandler; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +public class MetaTableExport extends ExportProgress implements ResultHandler> { + private final MetadataBasicVo metadata; + private Consumer queryFunc; + private final String fileName; + private JSONArray colsArray; + private final MetadataService metadataService; + + // 所有行的集合 + private List> rowList = new ArrayList<>(); + // 字段列名集合 + private List colNameList = new ArrayList<>(); + private int dataTotal; + + public MetaTableExport(String userId, MetadataBasicVo metadata) { + super(userId); + this.metadataService = AppContext.getContext().getBean(MetadataService.class); + this.metadata = metadata; + String name = metadata.getMetadataComment(); + if (!StringUtils.hasText(name)) { + name = metadata.getMetadataName(); + } + fileName = tempDir + File.separator + name + ".xlsx"; + } + + @Override + public void run() { + this.setTitle("正在读取数据表信息"); + colsArray = metadataService.getColumns(metadata.getId()); + + // 添加第一行,字段列名注释集合,当做表格的第一行 + rowList.add(colsArray.stream().map((json) -> { + JSONObject field = (JSONObject) json; + String comment = field.getString("comment"); + String colName = field.getString("columnName"); + colNameList.add(colName); + return colName + (StringUtils.hasText(comment) ? "[" + comment + "]" : ""); + }).collect(Collectors.toList())); + + this.setTitle("正在读取数据到临时文件"); + + // 执行数据查询 + try { + queryFunc.accept(null); + + File file = new File(fileName); + if(file.exists()){ + file.delete(); + } + List> rows = CollUtil.newArrayList(rowList); + //通过工具类创建writer + ExcelWriter writer = ExcelUtil.getWriter(file); + //一次性写出内容 + writer.write(rows); + //关闭writer,释放内存 + writer.close(); + this.setTitle("数据文件准备完毕,开始下载"); + this.setDone(); + } catch (Exception e) { + this.error = true; + this.setTitle("准备数据时出现异常"); + this.clean(); + } + } + + @Override + public long getStepTotal() { + return this.dataTotal; + } + + @Override + public String getDownloadPath() { + return this.fileName; + } + + @Override + public void handleResult(ResultContext> context) { + Map data = context.getResultObject(); + // 遍历字段列名,获取对应数据并拼接成列的集合 + List cells = colNameList.stream().map(col -> { + Object value = data.get(col); + value = value == null ? "" : value; + return String.valueOf(value); + }).collect(Collectors.toList()); + rowList.add(cells); + this.autoAddStep(); + } + + public void queryData(Consumer query) { + this.queryFunc = query; + } + + public void setDataCount(int count) { + this.dataTotal = count; + } +} diff --git a/shandan-system/src/main/java/com/keyware/shandan/bianmu/utils/MetadataUtils.java b/shandan-system/src/main/java/com/keyware/shandan/bianmu/utils/MetadataUtils.java index be7f6de..dd32fcb 100644 --- a/shandan-system/src/main/java/com/keyware/shandan/bianmu/utils/MetadataUtils.java +++ b/shandan-system/src/main/java/com/keyware/shandan/bianmu/utils/MetadataUtils.java @@ -24,6 +24,10 @@ import java.util.stream.Collectors; public class MetadataUtils { public static String generateSql(MetadataBasicVo metadata, DataSourceVo dataSource) { + return generateSql(metadata, dataSource, false); + } + + public static String generateSql(MetadataBasicVo metadata, DataSourceVo dataSource, boolean isCountSql) { StringBuilder builder = new StringBuilder(); String schema = dataSource.getJdbcSchema(); @@ -38,7 +42,7 @@ public class MetadataUtils { if (optional.isPresent()) { MetadataDetailsVo masterTable = optional.get(); JSONArray masterColumns = getColumns(masterTable); - if (masterColumns.size() > 0) { + if (!masterColumns.isEmpty()) { StringBuilder tableNameBuilder = new StringBuilder(); StringBuilder columnsBuilder = new StringBuilder(); StringBuilder wheresBuilder = new StringBuilder(); @@ -47,12 +51,14 @@ public class MetadataUtils { // 主表 String master_table = masterTable.getTableName(); - // 主表列 - masterColumns.forEach(o -> { - JSONObject obj = (JSONObject) o; - columnsBuilder.append(" \"").append(master_table).append("\".\"").append(obj.getString("columnName")).append("\","); - columnTemp.add(obj.getString("columnName")); - }); + if (!isCountSql) { + // 主表列 + masterColumns.forEach(o -> { + JSONObject obj = (JSONObject) o; + columnsBuilder.append(" \"").append(master_table).append("\".\"").append(obj.getString("columnName")).append("\","); + columnTemp.add(obj.getString("columnName")); + }); + } // 主表表名 tableNameBuilder.append(schema).append("\"").append(master_table).append("\" as \"").append(master_table).append("\""); @@ -66,18 +72,23 @@ public class MetadataUtils { MetadataDetailsVo table = tables.get(i); tableNameBuilder.append(", ").append(schema).append("\"").append(table.getTableName()).append("\" as \"").append(table.getTableName()).append("\""); - getColumns(table).forEach(obj -> { - JSONObject col = (JSONObject) obj; - if (!columnTemp.contains(col.getString("columnName"))) { - columnsBuilder.append("\"").append(table.getTableName()).append("\".\"").append(col.getString("columnName")).append("\","); - } - }); + if (!isCountSql) { + getColumns(table).forEach(obj -> { + JSONObject col = (JSONObject) obj; + if (!columnTemp.contains(col.getString("columnName"))) { + columnsBuilder.append("\"").append(table.getTableName()).append("\".\"").append(col.getString("columnName")).append("\","); + } + }); + } // where 条件 appendWhere(tables, table, wheresBuilder, "\"" + table.getTableName() + "\""); + } - builder.append("select ").append(columnsBuilder.substring(0, columnsBuilder.toString().length() - 1)) + String select = isCountSql ? " count(1) " : columnsBuilder.substring(0, columnsBuilder.toString().length() - 1); + + builder.append("select ").append(select) .append(" from ").append(tableNameBuilder) .append(" where 1=1 ").append(wheresBuilder); diff --git a/shandan-system/src/main/java/com/keyware/shandan/datasource/mapper/DynamicDatasourceMapper.java b/shandan-system/src/main/java/com/keyware/shandan/datasource/mapper/DynamicDatasourceMapper.java index 1ea3e7d..802c0f2 100644 --- a/shandan-system/src/main/java/com/keyware/shandan/datasource/mapper/DynamicDatasourceMapper.java +++ b/shandan-system/src/main/java/com/keyware/shandan/datasource/mapper/DynamicDatasourceMapper.java @@ -1,8 +1,13 @@ package com.keyware.shandan.datasource.mapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.keyware.shandan.bianmu.entity.DirectoryVo; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Options; +import org.apache.ibatis.annotations.ResultType; import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.mapping.ResultSetType; +import org.apache.ibatis.session.ResultHandler; import java.util.HashMap; import java.util.List; @@ -25,4 +30,11 @@ public interface DynamicDatasourceMapper { @Select("${sql}") Page> page(Page page, String sql); + @Select("${sql}") + @ResultType(HashMap.class) + @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = Integer.MIN_VALUE) + void listByHandler(String sql, ResultHandler> handler); + + @Select("${sql}") + int count(String sql); }