package com.product.patch.service; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.ZipUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.product.core.cache.DataPoolCacheImpl; import com.product.core.config.CoreConst; import com.product.core.config.Global; import com.product.core.entity.DataTableEntity; import com.product.core.entity.FieldSetEntity; import com.product.core.service.support.AbstractBaseService; import com.product.file.service.FileManagerService; import com.product.patch.config.CmnConst; import com.product.patch.config.ErrorCode; import com.product.tool.table.enums.FieldType; import com.product.util.BaseUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.Charset; import java.util.*; /** * @Author cheng * @Date 2024/10/23 10:07 * @Desc 补丁导出 */ @Service public class PatchExportService extends AbstractBaseService { @Resource private FileManagerService fileManagerService; public void export(FieldSetEntity fse, HttpServletResponse response) throws IOException { Set promptNameSet = new HashSet<>(); Set dictNameSet = new HashSet<>(); String checkedTable = fse.getString("checkedTable"); JSONArray tables = null; if (!StringUtils.isEmpty(checkedTable)) { tables = JSONArray.parseArray(checkedTable); } String exportData = fse.getString("exportData"); JSONObject exportDataObj = null; if (!StringUtils.isEmpty(exportData)) { exportDataObj = JSONArray.parseObject(exportData); } String exportFunction = fse.getString("exportFunction"); JSONArray exportFunctionArr = null; if (!StringUtils.isEmpty(exportFunction)) { exportFunctionArr = JSONArray.parseArray(exportFunction); } String exportFace = fse.getString("exportFace"); JSONArray exportFaceArr = null; if (!StringUtils.isEmpty(exportFace)) { exportFaceArr = JSONArray.parseArray(exportFace); } String exportFlow = fse.getString("exportFlow"); JSONArray exportFlowArr = null; if (!StringUtils.isEmpty(exportFlow)) { exportFlowArr = JSONArray.parseArray(exportFlow); } String exportReference = fse.getString("exportReference"); JSONObject exportReferenceObj = null; if (!StringUtils.isEmpty(exportReference)) { exportReferenceObj = JSONArray.parseObject(exportReference); } String tempDir = Global.getSystemConfig("temp.dir", "./attachment/file/temp"); //生成本次补丁文件夹 所有产生的临时文件放入该文件夹下 方便删除 File currentDir = new File(tempDir + "/" + getDateTime()); File tableStructureFile = exportTable(currentDir, tables, promptNameSet, dictNameSet); DataTableEntity attachments = new DataTableEntity(); File dataZipFile = exportBusinessData(currentDir, exportDataObj, attachments); File functionFile = exportFunction(currentDir, exportFunctionArr); File faceFile = exportFace(currentDir, exportFaceArr, promptNameSet, dictNameSet); File flowFile = exportFlow(currentDir, exportFlowArr, attachments); File referenceFile = exportReference(currentDir, exportReferenceObj); String zipFileName = currentDir + "/lx_" + getDateTime() + ".patch"; List fileList = new ArrayList<>(); if (tableStructureFile != null) { fileList.add(tableStructureFile); } if (dataZipFile != null) { fileList.add(dataZipFile); } if (functionFile != null) { fileList.add(functionFile); } if (faceFile != null) { fileList.add(faceFile); } if (flowFile != null) { fileList.add(flowFile); } if (referenceFile != null) { fileList.add(referenceFile); } File attachment = exportAttachment(currentDir, attachments); if (attachment != null) { fileList.add(attachment); } File zip = ZipUtil.zip(new File(zipFileName), Charset.defaultCharset(), false, fileList.toArray(new File[0])); response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); response.setHeader("Content-Disposition", "attachment; filename=" + zip.getName()); response.setContentType("application/octet-stream"); response.setContentLengthLong(zip.length()); OutputStream out = response.getOutputStream(); try { FileUtil.writeToStream(zip, out); } catch (Exception e) { e.printStackTrace(); //异常时输出类型改为json response.setContentType("application/json"); Map result = new HashMap<>(); result.put("code", ErrorCode.EXTRACT_FAIL.getValue()); result.put("msg", ErrorCode.EXTRACT_FAIL.getText()); result.put("status", "fail"); IoUtil.write(out, Charset.defaultCharset(), false, JSONObject.toJSONString(result)); logger.error("导出补丁文件异常", e); } out.flush(); out.close(); FileUtil.del(currentDir); } private File writeString(DataTableEntity dte, String fileName, File dir) { if (DataTableEntity.isEmpty(dte) || StringUtils.isEmpty(fileName)) { return null; } if (!fileName.startsWith("/") && !fileName.startsWith("\\")) { fileName = "/" + fileName; } JSONArray objects = BaseUtil.dataTableEntityToJson(dte); //将数据导出到文件 String data = objects.toJSONString(); File touch = FileUtil.touch(dir, fileName); FileUtil.writeString(data, touch, "UTF-8"); return touch; } public File exportReference(File dir, JSONObject exportReferenceObj) { if (exportReferenceObj == null) { return null; } //创建文件夹 File referenceDir = new File(dir.getPath() + File.separator + "reference"); if (!referenceDir.exists()) { referenceDir.mkdirs(); } JSONArray prompt = exportReferenceObj.getJSONArray("prompt"); JSONArray dict = exportReferenceObj.getJSONArray("dict"); if (prompt != null && prompt.size() > 0) { DataTableEntity dte = getBaseDao().listTable("product_sys_prompt", BaseUtil.buildQuestionMarkFilter("prompt_name", prompt.size(), true), prompt.toArray()); writeString(dte, "prompt_" + getDateTime(), referenceDir); } if (dict != null && dict.size() > 0) { DataTableEntity dte = getBaseDao().listTable("product_sys_dict", BaseUtil.buildQuestionMarkFilter("dict_name", dict.size(), true), dict.toArray()); writeString(dte, "dict_" + getDateTime(), referenceDir); } if (referenceDir.list().length > 0) { return ZipUtil.zip(referenceDir); } return null; } /** * 导出表结构 包含索引 * @param dir * @param tableInfoArr * @return */ public File exportTable(File dir, JSONArray tableInfoArr, Set promptNameSet, Set dictNameSet) { DataTableEntity tableDte = getBaseDao().listTable(CoreConst.PRODUCT_SYS_DATAMODEL_TABLE, BaseUtil.buildQuestionMarkFilter("table_name", tableInfoArr.size(), true), tableInfoArr.stream().toArray(), new Object[]{}, null, Integer.MAX_VALUE, 1, true); return writeString(tableDte, "table_" + getDateTime(), dir); } /** * 导出业务数据 * @param dir * @param exportDataObj * @return */ public File exportBusinessData(File dir, JSONObject exportDataObj, DataTableEntity attachments) { if (exportDataObj == null) { return null; } Set tableNameSet = exportDataObj.keySet(); if (CollectionUtil.isEmpty(tableNameSet)) { return null; } List fileList = new ArrayList<>(); for (String tableName : tableNameSet) { JSONObject conf = exportDataObj.getJSONObject(tableName); // 0 忽略数据 1 导出全部数据 2 导出指定数据 String dataExportType = conf.getString("dataExportType"); if ("0".equals(dataExportType)) { continue; } String filter = null; Object[] params = null; if ("2".equals(dataExportType)) { JSONArray selectionData = conf.getJSONArray("selectionData"); if (selectionData == null || selectionData.isEmpty()) { continue; } filter = BaseUtil.buildQuestionMarkFilter("uuid", selectionData.size(), true); params = selectionData.stream().toArray(); } DataTableEntity dte = getBaseDao().listTable(tableName, filter, params); if (DataTableEntity.isEmpty(dte)) { continue; } DataTableEntity dt = getAttachmentData(dte); if (!DataTableEntity.isEmpty(dt)) { BaseUtil.dataTableMerge(attachments, dt); } File file = writeString(dte, "data_" + tableName + "_" + getDateTime(), dir); fileList.add(file); } //压缩文件 File[] array = fileList.toArray(new File[]{}); File zip = new File(dir.getPath() + "/table_data" + getDateTime() + ".zip"); ZipUtil.zip(zip, Charset.defaultCharset(), false, array); return zip; } /** * 导出功能 * @param dir * @param exportFunctionArr * @return */ public File exportFunction(File dir, JSONArray exportFunctionArr) { if (exportFunctionArr == null || exportFunctionArr.isEmpty()) { return null; } DataTableEntity functionDte = getBaseDao().listTable(CoreConst.PRODUCT_SYS_FUNCTIONS, BaseUtil.buildQuestionMarkFilter("uuid", exportFunctionArr.size(), true), exportFunctionArr.stream().toArray(), new Object[]{}, null, Integer.MAX_VALUE, 1, true); return writeString(functionDte, "function_" + getDateTime(), dir); } public File exportFlow(File dir, JSONArray exportFlowArr, DataTableEntity attachments) { if (exportFlowArr == null || exportFlowArr.isEmpty()) { return null; } DataTableEntity flowDte = getBaseDao().listTable(CmnConst.TABLE_PRODUCT_SYS_FLOW_MODEL, BaseUtil.buildQuestionMarkFilter("type_code", exportFlowArr.size(), true), exportFlowArr.stream().toArray(), new Object[]{}, null, Integer.MAX_VALUE, 1, true); return writeString(flowDte, "flow_" + getDateTime(), dir); } public File exportFace(File dir, JSONArray exportFaceArr, Set promptNameSet, Set dictNameSet) { if (exportFaceArr == null || exportFaceArr.isEmpty()) { return null; } DataTableEntity faceDte = getBaseDao().listTable("product_sys_face", BaseUtil.buildQuestionMarkFilter("face_number", exportFaceArr.size(), true), exportFaceArr.stream().toArray(), new Object[]{}, null, Integer.MAX_VALUE, 1, true); return writeString(faceDte, "face_" + getDateTime(), dir); } public File exportAttachment(File dir, DataTableEntity attachments) { if (DataTableEntity.isEmpty(attachments)) { return null; } File attachmentDir = new File(dir.getPath() + File.separator + "/attachment"); for (int i = 0; i < attachments.getRows(); i++) { FieldSetEntity fieldSetEntity = attachments.getFieldSetEntity(i); try { File file = fileManagerService.getFile(fieldSetEntity); if (file != null && file.isFile()) { File tempFile = new File(attachmentDir.getPath() + File.separator + fieldSetEntity.getString("attachment_title")); if (!tempFile.getParentFile().exists()) { tempFile.getParentFile().mkdirs(); } if (!tempFile.exists()) { tempFile.createNewFile(); } FileUtil.copy(file, tempFile, true); FileUtil.del(file); } } catch (Exception e) { e.printStackTrace(); } } JSONArray objects = BaseUtil.dataTableEntityToJson(attachments); String data = objects.toJSONString(); File touch = FileUtil.touch(dir, "/attachment_data" + getDateTime()); FileUtil.writeString(data, touch, "UTF-8"); File zip = ZipUtil.zip(new File(dir.getPath() + "/attachment" + getDateTime() + ".zip"), Charset.defaultCharset(), true, touch, attachmentDir); return zip; } private DataTableEntity getAttachmentData(DataTableEntity dte) { if (DataTableEntity.isEmpty(dte)) { return null; } String tableName = dte.getTableName().toString(); FieldSetEntity tableInfo = BaseUtil.getSingleInfoByCache("所有表信息", new String[]{tableName}); if (FieldSetEntity.isEmpty(tableInfo)) { return null; } String tableUuid = tableInfo.getString("uuid"); DataTableEntity fieldDte = DataPoolCacheImpl.getInstance().getCacheData("所有字段信息并按表分组", new String[]{tableUuid}); //获取所有附件字段 Set attachmentField = new HashSet<>(); for (int i = 0; i < fieldDte.getRows(); i++) { String fieldType = fieldDte.getString(i, "field_type"); if (FieldType.FILE.equals(FieldType.getByDictValue(fieldType))) { attachmentField.add(fieldDte.getString(i, "field_name")); } } if (CollectionUtil.isEmpty(attachmentField)) { return null; } Set fileUuidSet = new HashSet<>(); for (int i = 0; i < dte.getRows(); i++) { for (String field : attachmentField) { String fileUuid = dte.getString(i, field); if (StringUtils.isEmpty(fileUuid)) { continue; } fileUuidSet.add(fileUuid); } } if (CollectionUtil.isEmpty(fileUuidSet)) { return null; } return getBaseDao().listTable("product_sys_attachments", BaseUtil.buildQuestionMarkFilter("uuid", fileUuidSet.size(), true), fileUuidSet.toArray()); } private String getDateTime() { return DateTime.now().toString("yyyyMMddHHmmss"); } }