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.ArrayUtil; import cn.hutool.core.util.ZipUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Sets; import com.product.admin.service.PublicService; import com.product.common.utils.StringUtils; 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.exception.BaseException; import com.product.core.service.support.AbstractBaseService; import com.product.core.transfer.Transactional; import com.product.core.util.JsonUtil; import com.product.patch.config.CmnConst; import com.product.patch.service.idel.IPatchImportService; import com.product.tool.table.service.DataModelService; import com.product.util.BaseUtil; import com.sun.xml.internal.bind.v2.TODO; import org.apache.poi.ss.formula.functions.T; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.StandardCopyOption; import java.util.*; /** * @Author cheng * @Date 2024/10/23 10:07 * @Desc 补丁导出 */ @Service public class PatchImportService extends AbstractBaseService implements IPatchImportService { @Resource private PublicService publicService; @Resource private DataModelService dataModelService; @Override @Transactional public Map uploadPatchFile(File patchFile) throws Exception { Map result = new HashMap<>(); File patchDir = ZipUtil.unzip(patchFile); //获取文件夹下的所有文件 File[] files = patchDir.listFiles(); //文件排序将zip排到最后 Arrays.sort(files, (a, v) -> { if (a.getName().endsWith(".zip")) { return 1; } else { return -1; } }); for (File file : files) { if (!file.isFile()) { continue; } String fileName = file.getName(); if (fileName.startsWith("face_")) { //表单 readFaceData(file); } else if (fileName.startsWith("flow_")) { //流程 readFlowData(file); } else if (fileName.startsWith("function_")) { //功能 readFunctionData(file); } else if (fileName.startsWith("structure_")) { //数据表 readTableStructure(file); } else if (fileName.startsWith("attachment") && fileName.endsWith(".zip")) { //附件 readAttachment(file); } else if (fileName.startsWith("table_data") && fileName.endsWith(".zip")) { //数据 readTableData(file); } else if (fileName.startsWith("reference") && fileName.endsWith(".zip")) { //参照 readReference(file); } } return result; } /** * 读取参照 */ private Integer readReference(File file) throws Exception { if (!file.isFile()) { return 0; } File unzip = ZipUtil.unzip(file); //解压的文件下 有 prompt 文件 和 dict 文件 在目录下找到这两个文件 File dict = new File(unzip.getPath() + File.separator + "dict"); File prompt = new File(unzip.getPath() + File.separator + "prompt"); DataTableEntity dictDte = readFileData(dict, "product_sys_dict"); DataTableEntity promptDte = readFileData(prompt, "product_sys_prompt"); return addOrUpdate(dictDte) + addOrUpdate(promptDte); } private Integer addOrUpdate(DataTableEntity dte) { if (DataTableEntity.isEmpty(dte)) { return 0; } String tableName = dte.getTableName().toString(); //获取uuid Object[] uuids = dte.getUuids(); DataTableEntity dte1 = getBaseDao().listTable(tableName, BaseUtil.buildQuestionMarkFilter("uuid", uuids.length, true), uuids); Set subTableNames = Sets.newHashSet(); for (int i = 0; i < dte.getRows(); i++) { String uuid = dte1.getString(i, CoreConst.UUID); FieldSetEntity ff = dte1.getFieldSetEntity(i); if (ff.getSubData() != null) { subTableNames.addAll(ff.getSubData().keySet()); } List fieldSetEntity = dte1.getFieldSetEntity(uuid); if (!CollectionUtil.isEmpty(fieldSetEntity)) { continue; } FieldSetEntity fse = fieldSetEntity.get(0); fse.setValue(CoreConst.SYSTEM_DATA_OPERATE_TYPE, CoreConst.SYSTEM_DATA_OPERATE_ADD); } for (String subTableName : subTableNames) { FieldSetEntity info = BaseUtil.getSingleInfoByCache("所有表信息", new String[]{subTableName}); if (info == null) { continue; } FieldSetEntity info1 = BaseUtil.getSingleInfoByCache("所有表关联信息", new String[]{info.getUUID()}); if (FieldSetEntity.isEmpty(info1)) { continue; } getBaseDao().delete(subTableName, BaseUtil.buildQuestionMarkFilter(info1.getString("field_name"), dte1.getRows(), true), uuids); } getBaseDao().update(dte); return dte.getRows(); } /** * 读取表结构数据 * @param file * @return * @throws Exception */ private DataTableEntity readTableStructure(File file) throws Exception { DataTableEntity dte = readFileData(file, "product_sys_datamodel_table"); DataTableEntity old = getBaseDao().listTable("product_sys_datamodel_table", BaseUtil.buildQuestionMarkFilter("uuid", dte.getUuids().length, true), dte.getUuids(), null, null, Integer.MAX_VALUE, 1, true); for (int i = 0; i < dte.getRows(); i++) { FieldSetEntity fse = dte.getFieldSetEntity(i); //查询出不存在的索引和字段 if (old != null && old.getRows() > 0) { List oldf = old.getFieldSetEntity(fse.getString("uuid")); if (CollectionUtil.isEmpty(oldf)) { //记录不存在 、新表 continue; } FieldSetEntity oldFse = oldf.get(0); //对比索引和字段 String[] table = {"product_sys_datamodel_field", "product_sys_datamodel_index"}; for (String t : table) { DataTableEntity sub = fse.getSubDataTable(t); DataTableEntity oldSub = oldFse.getSubDataTable(t); if (DataTableEntity.isEmpty(oldSub)) { continue; } // 补丁中子表为空 则全删除 if (DataTableEntity.isEmpty(sub)) { sub = old.clones(); //设置为删除 for (int i1 = 0; i1 < sub.getRows(); i1++) { sub.setFieldValue(i1, CoreConst.SYSTEM_DATA_OPERATE_TYPE, CoreConst.SYSTEM_DATA_OPERATE_DEL); } continue; } //删除当前已存在的字段但补丁中没有的 for (int i1 = 0; i1 < oldSub.getRows(); i1++) { FieldSetEntity oldFse1 = oldSub.getFieldSetEntity(i1); List fieldSetEntity = sub.getFieldSetEntity(oldFse1.getString("uuid")); if (CollectionUtil.isEmpty(fieldSetEntity)) { //不存在 FieldSetEntity clones = oldFse1.clones(); clones.setValue(CoreConst.SYSTEM_DATA_OPERATE_TYPE, CoreConst.SYSTEM_DATA_OPERATE_DEL); sub.addFieldSetEntity(clones); } } } } //调用数据建模统一操作方法 dataModelService.dataModelOperation(fse); } return null; } /** * 读取流程配置 * @param file * @return * @throws Exception */ private Integer readFlowData(File file) throws Exception { DataTableEntity dataTableEntity = readFileData(file, "product_sys_flow"); return addOrUpdate(dataTableEntity); } /** * 读取功能配置 * @param file * @return * @throws Exception */ private int readFunctionData(File file) throws Exception { DataTableEntity dte = readFileData(file, "product_sys_functions"); //判断是否已经存在 且 tricode 不一致 if (DataTableEntity.isEmpty(dte)) { return 0; } String tableName = dte.getTableName().toString(); //获取uuid Object[] uuids = dte.getUuids(); DataTableEntity dte1 = getBaseDao().listTable(tableName, BaseUtil.buildQuestionMarkFilter("uuid", uuids.length, true), uuids); Set subTableNames = Sets.newHashSet(); for (int i = 0; i < dte.getRows(); i++) { String uuid = dte1.getString(i, CoreConst.UUID); FieldSetEntity ff = dte1.getFieldSetEntity(i); if (ff.getSubData() != null) { subTableNames.addAll(ff.getSubData().keySet()); } List fieldSetEntity = dte1.getFieldSetEntity(uuid); if (!CollectionUtil.isEmpty(fieldSetEntity)) { //判断tricode 是否一致 FieldSetEntity fieldSetEntity1 = fieldSetEntity.get(0); String tricode = fieldSetEntity1.getString("tricode"); String tricode1 = dte.getString(i, "tricode"); if (StringUtils.isNotEmpty(tricode) && !tricode.equals(tricode1)) { //不一致 String triCodeParent = fieldSetEntity1.getString("tricode_parent"); String triCodeParent1 = dte.getString(i, "tricode_parent"); if (StringUtils.isNotEmpty(triCodeParent) && !triCodeParent.equals(triCodeParent1)) { //拿到已存在的tricode 替换 dte.setFieldValue(i, "tricode", tricode); dte.setFieldValue(i, "tricode_parent", triCodeParent); continue; } else { //重新生成 dte.setFieldValue(i, "tricode", null); publicService.createdCode(dte.getFieldSetEntity(i), "product_sys_functions", "tricode", "tricode_parent"); } continue; } continue; } for (String subTableName : subTableNames) { FieldSetEntity info = BaseUtil.getSingleInfoByCache("所有表信息", new String[]{subTableName}); if (info == null) { continue; } FieldSetEntity info1 = BaseUtil.getSingleInfoByCache("所有表关联信息", new String[]{info.getUUID()}); if (FieldSetEntity.isEmpty(info1)) { continue; } getBaseDao().delete(subTableName, BaseUtil.buildQuestionMarkFilter(info1.getString("field_name"), dte1.getRows(), true), uuids); } FieldSetEntity fse = fieldSetEntity.get(0); fse.setValue(CoreConst.SYSTEM_DATA_OPERATE_TYPE, CoreConst.SYSTEM_DATA_OPERATE_ADD); } getBaseDao().update(dte); return dte.getRows(); } /** * 读取表单配置 * @param file * @return * @throws Exception */ private int readFaceData(File file) throws Exception { DataTableEntity dte = readFileData(file, "product_sys_form"); return addOrUpdate(dte); } /** * 数据业务表数据 * @param file * @return * @throws Exception */ private int readTableData(File file) throws Exception { if (!file.isFile()) { return 0; } File fileDir = ZipUtil.unzip(file); int result = 0; for (File file1 : fileDir.listFiles()) { if (!file1.isFile()) { continue; } String fileName = file1.getName(); //判断文件名是否以data_开头 中间任意字母+下划线 结尾是 _ + 16位数字 String regex = "^data_.*_[0-9]{14}$"; if (!fileName.matches(regex)) { continue; } String tableName = fileName.substring(5, fileName.length() - 15); DataTableEntity res = readFileData(file1, tableName); if (DataTableEntity.isEmpty(res)) { continue; } result += addOrUpdate(res); } return result; } /** * 读取附件数据并保存 * @param file * @throws Exception */ private void readAttachment(File file) throws Exception { File unzip = ZipUtil.unzip(file); //去读文件夹中的文件 File[] files = unzip.listFiles((v) -> v.isFile()); if (files.length == 0) { return; } File attachmentFile = files[0]; String fileName = attachmentFile.getName(); JSONArray data = null; if (fileName.startsWith("attachment_data")) { //附件数据 data = readFileString(attachmentFile); } else { return; } if (data == null || data.isEmpty()) { return; } DataTableEntity attachmentDte = toDataTable(data, "product_sys_attachments"); //去读附件文件 File attachmentDir = new File(unzip.getPath() + File.separator + "attachment"); Object[] uuids = attachmentDte.getUuids(); DataTableEntity dte = getBaseDao().listTable("product_sys_attachments", BaseUtil.buildQuestionMarkFilter("uuid", uuids.length, true), uuids); for (int i = 0; i < attachmentDte.getRows(); i++) { FieldSetEntity fse = attachmentDte.getFieldSetEntity(i); //获取数据对应的附件 String attachmentTitle = fse.getString("attachment_title"); File file1 = new File(attachmentDir + File.separator + attachmentTitle); if (!file1.isFile()) { continue; } //移动到附件对应的目录 String path = fse.getString("attachment_url"); String dir = Global.getSystemConfig("local.dir", "./attachment/file"); File targetDir = new File(dir + File.separator + path); if (!targetDir.exists()) { targetDir.mkdirs(); } //复制文件到直接文件夹 存在替换 FileUtil.copyFile(file1, targetDir, StandardCopyOption.REPLACE_EXISTING); List fieldSetEntity = dte.getFieldSetEntity(fse.getUUID()); if (fieldSetEntity == null || fieldSetEntity.isEmpty()) { //新数据 fse.setValue(CoreConst.SYSTEM_DATA_OPERATE_TYPE, CoreConst.SYSTEM_DATA_OPERATE_ADD); } } getBaseDao().update(attachmentDte); } /** * 读取文件中的数据并转为DataTable * @param file * @param tableName * @return * @throws Exception */ private DataTableEntity readFileData(File file, String tableName) throws Exception { if (!file.isFile()) { return null; } JSONArray objects = readFileString(file); if (objects == null || objects.isEmpty()) { return null; } return toDataTable(objects, tableName); } /** * json数组转DataTable * @param arr * @param tableName * @return */ private DataTableEntity toDataTable(JSONArray arr, String tableName) throws BaseException { if (arr == null || arr.isEmpty()) { return null; } DataTableEntity result = new DataTableEntity(); //遍历json数组 for (int i = 0; i < arr.size(); i++) { FieldSetEntity fse = new FieldSetEntity(tableName); JSONObject jsonObject = arr.getJSONObject(i); fse.setValues((Map) jsonObject.clone()); //将json中装载的json对象转成DataTableEntity,遍历json中的内容 for (String key : jsonObject.keySet()) { Object o = jsonObject.get(key); if (o instanceof JSONArray) { fse.remove(key); fse.addSubDataTable(toDataTable(jsonObject.getJSONArray(key), key)); } } result.addFieldSetEntity(fse); } return result; } /** * 读取文件中的内容 * @param file * @return */ private JSONArray readFileString(File file) throws Exception { if (!file.isFile()) { return null; } try (InputStream in = new FileInputStream(file)) { String str = IoUtil.read(in, "UTF-8"); if (StringUtils.isEmpty(str)) { return null; } return JSONArray.parseArray(str); } } private String getDateTime() { return DateTime.now().toString("yyyyMMddHHmmss"); } }