From 9abe5ef820d77c44073774f7187d26215eb7a637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Wed, 20 Dec 2023 14:53:31 +0800 Subject: [PATCH] 'commit' --- .../ImportExcel/Backup/createTable.java | 457 ++++++++++++++++++ .../UnitTest/ImportExcel/Bean/CellBean.java | 46 +- .../UnitTest/ImportExcel/ImportExcelData.java | 49 ++ .../QingLong/Util/GenericTemplateUtil.java | 16 +- .../b61a2af2-223f-4058-a675-b212e4dd9487.xlsx | Bin 20542 -> 20769 bytes 5 files changed, 548 insertions(+), 20 deletions(-) create mode 100644 src/main/java/UnitTest/ImportExcel/Backup/createTable.java create mode 100644 src/main/java/UnitTest/ImportExcel/ImportExcelData.java diff --git a/src/main/java/UnitTest/ImportExcel/Backup/createTable.java b/src/main/java/UnitTest/ImportExcel/Backup/createTable.java new file mode 100644 index 00000000..598446f9 --- /dev/null +++ b/src/main/java/UnitTest/ImportExcel/Backup/createTable.java @@ -0,0 +1,457 @@ +package UnitTest.ImportExcel.Backup; + +import UnitTest.ImportExcel.Bean.CellBean; +import com.dsideal.QingLong.Util.ChineseCharacterUtil; +import com.jfinal.kit.Kv; +import com.jfinal.kit.PropKit; +import com.jfinal.kit.StrKit; +import com.jfinal.plugin.activerecord.ActiveRecordPlugin; +import com.jfinal.plugin.activerecord.CaseInsensitiveContainerFactory; +import com.jfinal.plugin.activerecord.Db; +import com.jfinal.plugin.activerecord.Record; +import com.jfinal.plugin.activerecord.dialect.PostgreSqlDialect; +import com.jfinal.plugin.hikaricp.HikariCpPlugin; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.util.LocaleUtil; +import org.apache.poi.xssf.usermodel.XSSFColor; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +public class createTable { + + /** + * 功能:移除小括号,以及小括号内的文字内容 + * + * @param input + * @return + */ + public static String removeKuoHao(String input) { + String output = input.replaceAll("\\(.*?\\)", ""); + output = output.replaceAll("\\(.*?\\)", ""); + return output; + } + + /** + * 功能:移除字符串中的数字 + * + * @param input + * @return + */ + public static String removeNumbers(String input) { + String regex = "\\d+"; // 匹配数字的正则表达式 + String result = input.replaceAll(regex, ""); // 使用replaceAll方法将匹配到的数字替换为空字符串 + return result; + } + + /** + * ) + * 获取单元格vo + * + * @param cell 单元格 + * @return + */ + private static CellBean getCellBean(Cell cell) { + CellBean dto = new CellBean();//创建单元格对象 + if (cell != null) { + //值 + switch (cell.getCellType()) { + case NUMERIC://导入数据,没有支持到时间的,一般都是到日期为止 + if (DateUtil.isCellDateFormatted(cell)) { + DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", LocaleUtil.getUserLocale()); + sdf.setTimeZone(LocaleUtil.getUserTimeZone()); + dto.setValue(sdf.format(cell.getDateCellValue())); + dto.setType("Date"); + } else { + String type; + Long longVal = Math.round(cell.getNumericCellValue()); + Double doubleVal = cell.getNumericCellValue(); + if (Double.parseDouble(longVal + ".0") == doubleVal) { //判断是否含有小数位.0 + type = "int"; + } else { + type = "float8"; + } + DataFormatter formatter = new DataFormatter(); + dto.setValue(formatter.formatCellValue(cell)); + dto.setType(type); + } + break; + case STRING: + dto.setValue(cell.getStringCellValue()); + dto.setType("varchar(1024)"); + break; + case BOOLEAN: + dto.setValue(String.valueOf(cell.getBooleanCellValue())); + dto.setType("bool"); + break; + case FORMULA: + dto.setValue(cell.getCellFormula()); + dto.setType("varchar(1024)"); + break; + case BLANK: + dto.setValue(""); + dto.setType("varchar(1024)"); + break; + case ERROR: + dto.setValue(ErrorEval.getText(cell.getErrorCellValue())); + dto.setType("varchar(1024)"); + break; + default: { + dto.setValue("Unknown Cell Type: " + cell.getCellType()); + dto.setType("varchar(1024)"); + } + } + // xlsx 07版 + //背景颜色 + CellStyle cellStyle = cell.getCellStyle(); + XSSFColor xssfColor = (XSSFColor) cellStyle.getFillForegroundColorColor(); + byte[] bytes; + if (xssfColor != null) { + bytes = xssfColor.getRGB(); + dto.setBackgroundColor(String.format("#%02X%02X%02X", bytes[0], bytes[1], bytes[2])); + } + } + return dto; + } + + /** + * 功能:查找指定Sheet中的表头开始位置与结束位置,目前只支持一个Sheet一个导入模板,并且,只支持单行或双行表头 + * + * @param sheet + * @return + */ + public static List getHead(XSSFSheet sheet) { + List _list = new ArrayList<>(); + //整行都是同一种颜色的,视为表头 + // 遍历行 + for (int i = 0; i <= sheet.getLastRowNum(); i++) { + //获得行 + Row row = sheet.getRow(i); + //遍历列 + if (row != null) { + Map _map = new HashMap<>(); + for (int j = 0; j < row.getLastCellNum(); j++) { + //获取单元格 + Cell cell = row.getCell(j); + if (cell == null) continue; + CellBean eo = getCellBean(cell); + if (_map.containsKey(eo.getBackgroundColor())) + _map.put(eo.getBackgroundColor(), _map.get(eo.getBackgroundColor()) + 1); + else + _map.put(eo.getBackgroundColor(), 1); + } + if (_map.size() == 1 && _map.entrySet().iterator().next().getKey().startsWith("#")) { + _list.add(i + 1); + } + } + } + return _list; + } + + /** + * 功能:根据样例数据,获取生成物理表的字段类型 + * + * @param sheet + * @param st + * @param ed + * @return + */ + public static List> getStruct(XSSFSheet sheet, int st, int ed) { + List> list = new ArrayList<>(); + // 遍历行 + for (int i = st; i <= ed; i++) { + //获得行 + Row row = sheet.getRow(i); + List r = new ArrayList<>(); + //遍历列 + if (row != null) { + for (int j = 0; j < row.getLastCellNum(); j++) { + Cell cell = row.getCell(j); + if (cell == null) continue; + CellBean eo = getCellBean(cell); + r.add(eo.getType()); + } + } + list.add(r); + } + return list; + } + + /** + * 功能:判断表是不是存在 + * + * @param tableName + * @return + */ + public static boolean isTableExist(String tableName) { + String sql = "select count(*) as c from pg_class where relname = ?"; + return Db.findFirst(sql, tableName).getInt("c") == 1; + } + + /** + * 功能:检查两个EXCEL文件的指定行+指定列是不是内容一致,返回值是不一致的位置集合,位置用数对 Map.Entry描述 + * + * @param f1 模板文件 + * @param f2 上传文件 + * @param startRow 开始行 + * @param endRow 结束行 + * @param startCol 开始列 + * @param endCol 结束列 + * @return 不一样的位置集合 + * @throws IOException + */ + public static List> checkYiZhi(String f1, String f2, int startRow, int endRow, int startCol, int endCol) throws IOException { + FileInputStream file1 = new FileInputStream(f1); + FileInputStream file2 = new FileInputStream(f2); + List> errList = new ArrayList<>(); + Workbook wb1 = WorkbookFactory.create(file1); + Workbook wb2 = WorkbookFactory.create(file2); + + Sheet sheet1 = wb1.getSheetAt(0); + Sheet sheet2 = wb2.getSheetAt(0); + + for (int i = startRow; i <= endRow; i++) { + Row row1 = sheet1.getRow(i); + Row row2 = sheet2.getRow(i); + for (int j = startCol; j <= endCol; j++) { + Cell cell1 = row1.getCell(j); + Cell cell2 = row2.getCell(j); + if (cell1 != null && cell2 != null) { + if (!cell1.getStringCellValue().equals(cell2.getStringCellValue())) { + Map.Entry pair = new AbstractMap.SimpleEntry<>((i + 1), (j + 1)); + errList.add(pair); + } + } + } + } + file1.close(); + file2.close(); + return errList; + } + + /** + * 功能:创建表 + * + * @param tableName 表名 + * @param filePath excel文件位置 + * @throws IOException + */ + public static Kv createTable(String tableName, String filePath) throws IOException { + Kv kv = Kv.create(); + if (isTableExist(tableName)) { + kv.set("success", false); + kv.set("message", "表名:" + tableName + "已存在,不能创建,请手动更换!"); + return kv; + } + String colSql = "", commentSql = ""; + + InputStream is = new FileInputStream(filePath); + XSSFWorkbook wb = new XSSFWorkbook(is); + //读取sheet页 + XSSFSheet sheet = wb.getSheetAt(0); + //找到表头 + List _list = getHead(sheet); + + //遍历每一列,获取列信息,数据类型 + List> a = getStruct(sheet, _list.get(_list.size() - 1) + 1, sheet.getLastRowNum() + 1); + List b = a.get(0); + + // 输出表头的文字 + Row ed = sheet.getRow(_list.get(_list.size() - 1) - 1);//下标从0开始 + Row st = sheet.getRow(_list.get(0) - 1);//下标从0开始 + + //非空列有哪些 + Set notNullSet = new HashSet<>(); + // 首行数据 + Row dataFirstRow = sheet.getRow(_list.get(_list.size() - 1)); + + for (int i = 0; i < dataFirstRow.getLastCellNum(); i++) { + Cell cell = dataFirstRow.getCell(i); + CellBean eo = getCellBean(cell); + if (eo.getBackgroundColor().equals("#FF0000")) { + notNullSet.add(i + 1); + } + } + + //需要记录此模板编号的第几列对应哪个字段,方便以后的数据写入 + Record _map[] = new Record[ed.getLastCellNum()]; + + String column_name, memo; + for (int colNum = 0; colNum < ed.getLastCellNum(); colNum++) { + if (StrKit.isBlank(ed.getCell(colNum).toString())) { + memo = removeKuoHao(st.getCell(colNum).toString()); + column_name = ChineseCharacterUtil.getColumnNameByMemo(removeKuoHao(st.getCell(colNum).toString())); + } else { + int k = colNum; + while (StrKit.isBlank(st.getCell(k).toString())) k--; + memo = removeKuoHao(st.getCell(k).toString()) + + "_" + removeKuoHao(ed.getCell(colNum).toString()); + column_name = ChineseCharacterUtil.getColumnNameByMemo(removeKuoHao(st.getCell(k).toString())) + + "_" + ChineseCharacterUtil.getColumnNameByMemo(removeKuoHao(ed.getCell(colNum).toString())); + } + Record r = new Record(); + r.set("memo", memo); + r.set("column_name", column_name); + r.set("column_type", b.get(colNum)); + _map[colNum] = r; + colSql += "\"" + column_name + "\" " + b.get(colNum); + if (notNullSet.contains(colNum + 1)) colSql += " NOT NULL"; + colSql += ","; + commentSql += "COMMENT ON COLUMN \"public\".\"" + tableName + "\".\"" + column_name + "\" IS '" + memo + "';\n"; + } + String finalSql = "CREATE TABLE \"public\".\"" + tableName + "\" ("; + finalSql += "\"id\" serial4,"; + finalSql += colSql; + finalSql += "PRIMARY KEY (\"id\")"; + finalSql += ");\n"; + + finalSql += "COMMENT ON COLUMN \"public\".\"" + tableName + "\".\"id\" IS '主键,自增长ID';\n"; + finalSql += commentSql; + + Db.update(finalSql); + + //写入模板与表结构的关系t_importexcel_mapping + String sql = "delete from t_importexcel_mapping where table_name=?"; + Db.update(sql, tableName); + List list = new ArrayList<>(); + for (int i = 0; i < _map.length; i++) { + Record record = new Record(); + record.set("table_name", tableName); + record.set("column_name", _map[i].getStr("column_name")); + record.set("excel_column_idx", i + 1); + record.set("memo", _map[i].getStr("memo")); + record.set("column_type", removeNumbers(removeKuoHao(_map[i].getStr("column_type")))); + list.add(record); + } + Db.batchSave("t_importexcel_mapping", list, 100); + + //写入t_importexcel_config + sql = "delete from t_importexcel_config where table_name=?"; + Db.update(sql, tableName); + Record record = new Record(); + record.set("table_name", tableName); + record.set("excel_module_filename", "先不写上去"); + record.set("data_start_row", _list.get(_list.size() - 1) + 1); + record.set("column_num", ed.getLastCellNum()); + Db.save("t_importexcel_config", "table_name", record); + + wb.close(); + kv.set("success", true); + kv.set("message", "恭喜,表结构创建成功!"); + return kv; + } + + /** + * 功能:删除表 + * + * @param tableName + */ + public static void dropTable(String tableName) { + String sql = "drop table if exists " + tableName; + Db.update(sql); + } + + /** + * 功能:导入数据 + * + * @param table_name + * @param filePath + * @throws IOException + * @throws ParseException + */ + public static void importData(String table_name, String filePath) throws IOException, ParseException { + InputStream is = new FileInputStream(filePath); + XSSFWorkbook wb = new XSSFWorkbook(is); + //读取sheet页 + XSSFSheet sheet = wb.getSheetAt(0); + //通过表名获取到它的读取起始行,终止列 + String sql = "select * from t_importexcel_config where table_name=?"; + Record record = Db.findFirst(sql, table_name); + int data_start_row = record.getInt("data_start_row"); + int column_num = record.getInt("column_num"); + //获取字段与EXCEL列的映射信息 + sql = "select * from t_importexcel_mapping where table_name=?"; + List list = Db.find(sql, table_name); + Map _map = new HashMap<>(); + for (Record r : list) { + int excel_column_idx = r.getInt("excel_column_idx"); + String column_name = r.getStr("column_name"); + String column_type = r.getStr("column_type"); + Record rt = new Record(); + rt.set("column_name", column_name); + rt.set("column_type", column_type); + _map.put(excel_column_idx, rt); + } + //开始读取数据 + List writeList = new ArrayList<>(); + for (int i = data_start_row - 1; i <= sheet.getLastRowNum(); i++) { + //获得行 + Row row = sheet.getRow(i); + //遍历列 + if (row != null) { + Record writeRecord = new Record(); + for (int j = 0; j < column_num; j++) { + Cell cell = row.getCell(j); + CellBean bean = getCellBean(cell); + String colType = _map.get(j + 1).getStr("column_type"); + String colName = _map.get(j + 1).getStr("column_name"); + if (colType.equals("int")) + writeRecord.set(colName, Integer.parseInt(bean.getValue())); + else if (colType.equals("varchar")) + writeRecord.set(colName, bean.getValue()); + else if (colType.equals("float")) + writeRecord.set(colName, Float.parseFloat(bean.getValue().toString())); + else if (colType.equals("date")) { + String dateString = bean.getValue(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + Date date = dateFormat.parse(dateString); + writeRecord.set(colName, date); + } + } + writeList.add(writeRecord); + } + } + // 写入数据 + Db.batchSave(table_name, writeList, 100); + //关闭excel + wb.close(); + } + + public static void main(String[] args) throws Exception { + //告之配置文件位置 + PropKit.use("application.properties"); + HikariCpPlugin hp = new HikariCpPlugin(PropKit.get("jdbcUrl"), PropKit.get("user"), + PropKit.get("password").trim(), PropKit.get("driverClassName")); + hp.start(); + // 配置ActiveRecord插件 + ActiveRecordPlugin arp = new ActiveRecordPlugin(hp); + //配置默认小写 + arp.setContainerFactory(new CaseInsensitiveContainerFactory(true)); + arp.setDialect(new PostgreSqlDialect()); + arp.start(); + + //测试两个导入模板 + String workingPath = "D:\\dsWork\\QingLong\\src\\main\\java\\UnitTest\\ImportExcel\\"; + String filePath = workingPath + "测试1.xlsx"; + String tableName = "ds_gtzz_t_bmwj";//表名,研发人员在界面上录入,程序需要检查此表名是不是存在,如果存在返回错误信息,不存在,则可以生成创建表的SQL语句 + dropTable(tableName); + createTable(tableName, filePath); + importData(tableName, filePath); + + filePath = workingPath + "测试2.xlsx"; + tableName = "ds_gtzz_t_zc";//表名,研发人员在界面上录入,程序需要检查此表名是不是存在,如果存在返回错误信息,不存在,则可以生成创建表的SQL语句 + dropTable(tableName); + createTable(tableName, filePath); + importData(tableName, filePath); + + System.out.println("恭喜,所有操作成功完成!"); + } +} diff --git a/src/main/java/UnitTest/ImportExcel/Bean/CellBean.java b/src/main/java/UnitTest/ImportExcel/Bean/CellBean.java index a12e063c..0520aaab 100644 --- a/src/main/java/UnitTest/ImportExcel/Bean/CellBean.java +++ b/src/main/java/UnitTest/ImportExcel/Bean/CellBean.java @@ -1,27 +1,35 @@ package UnitTest.ImportExcel.Bean; + /** + * 单元格vo + */ + public class CellBean { + private String value = "";//值 + private String backgroundColor = "";//背景色 + private String fontColor = "";//文字颜色 -/** - * 单元格vo - */ -public class CellBean { - private String value = "";//值 - private String backgroundColor = "";//背景色 + private String type=""; + public String getValue() { + return value; + } - public String getValue() { - return value; - } + public void setValue(String value) { + this.value = value; + } - public void setValue(String value) { - this.value = value; - } + public String getBackgroundColor() { + return backgroundColor; + } - public String getBackgroundColor() { - return backgroundColor; - } + public void setBackgroundColor(String backgroundColor) { + this.backgroundColor = backgroundColor; + } - public void setBackgroundColor(String backgroundColor) { - this.backgroundColor = backgroundColor; - } + public String getType() { + return type; + } -} + public void setType(String type) { + this.type = type; + } + } diff --git a/src/main/java/UnitTest/ImportExcel/ImportExcelData.java b/src/main/java/UnitTest/ImportExcel/ImportExcelData.java new file mode 100644 index 00000000..4f429240 --- /dev/null +++ b/src/main/java/UnitTest/ImportExcel/ImportExcelData.java @@ -0,0 +1,49 @@ +package UnitTest.ImportExcel; + +import com.aspose.cells.Workbook; +import com.dsideal.QingLong.Util.AsposeUtil; +import com.jfinal.kit.PropKit; +import com.jfinal.plugin.activerecord.ActiveRecordPlugin; +import com.jfinal.plugin.activerecord.CaseInsensitiveContainerFactory; +import com.jfinal.plugin.activerecord.dialect.PostgreSqlDialect; +import com.jfinal.plugin.hikaricp.HikariCpPlugin; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class ImportExcelData { + public static String path = "D:\\dsWork\\QingLong\\src\\main\\resource\\Excel\\"; + + //模拟上传文件的文件名称 + public static String upload_excel_filename = "b61a2af2-223f-4058-a675-b212e4dd9487" + ".xlsx"; + + public static void main(String[] args) throws IOException { + //加载License + AsposeUtil.getLicense(); + + //告之配置文件位置 + PropKit.use("application.properties"); + HikariCpPlugin hp = new HikariCpPlugin(PropKit.get("jdbcUrl"), PropKit.get("user"), + PropKit.get("password").trim(), PropKit.get("driverClassName")); + hp.start(); + // 配置ActiveRecord插件 + ActiveRecordPlugin arp = new ActiveRecordPlugin(hp); + //配置默认小写 + arp.setContainerFactory(new CaseInsensitiveContainerFactory(true)); + arp.setDialect(new PostgreSqlDialect()); + arp.start(); + + //源文件 + String source = path + File.separator + upload_excel_filename; + + //解析上传EXCEL中的每个Sheet,解析出表头信息,表名描述等信息 + InputStream is = new FileInputStream(source); + XSSFWorkbook wb = new XSSFWorkbook(is); + + //关闭POI的工作簿 + wb.close(); + } +} diff --git a/src/main/java/com/dsideal/QingLong/Util/GenericTemplateUtil.java b/src/main/java/com/dsideal/QingLong/Util/GenericTemplateUtil.java index 0458c6d5..2e0c73c5 100644 --- a/src/main/java/com/dsideal/QingLong/Util/GenericTemplateUtil.java +++ b/src/main/java/com/dsideal/QingLong/Util/GenericTemplateUtil.java @@ -193,6 +193,20 @@ public class GenericTemplateUtil { return kv; } + /** + * 功能:PG数据库数据类型与EXCEL中数据类型的转换关系 + * @param pgColumnDataType + * @return + */ + public static String convertDataType(String pgColumnDataType) { + String res = "String"; + if (pgColumnDataType.startsWith("varchar")) res = "String"; + else if (pgColumnDataType.equals("int")) res = "Integer"; + else if (pgColumnDataType.equals("double")) res = "Double"; + else if (pgColumnDataType.equals("date")) res = "Date"; + return res; + } + /** * 功能:创建表 * @@ -240,7 +254,7 @@ public class GenericTemplateUtil { record.set("column_name", list.get(i).getStr("column_name")); record.set("excel_column_idx", i + 1); record.set("memo", list.get(i).getStr("memo")); - record.set("column_type", list.get(i).getStr("column_type")); + record.set("column_type", convertDataType(list.get(i).getStr("column_type"))); record.set("upload_excel_filename", upload_excel_filename); writeList.add(record); } diff --git a/src/main/resource/Excel/b61a2af2-223f-4058-a675-b212e4dd9487.xlsx b/src/main/resource/Excel/b61a2af2-223f-4058-a675-b212e4dd9487.xlsx index d5ef9c7bf521d5d6390fc7c008d50877ed72607d..01a40892828accbd93749d3f45126deec1b18ca4 100644 GIT binary patch delta 11190 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 bzu)73Hu@_2rxB$rJeXb$69G!;`QrZ%8o{P~ delta 10939 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 G<^KTWZg_+M