前言
當我們在寫設計文檔,或者是其他涉及到數據架構、表結構時,可以用POI來批量生成表格,例如下面的表格
代碼編寫
引入POI依賴
<!-- 引入apache poi --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.0.1</version> </dependency>
封裝兩個工具類
ExcelUtil,POI操作Excel工具類
import org.apache.poi.hssf.usermodel.*; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.util.StringUtils; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * POI操作Excel工具類 */ public class ExcelUtil { /** * 讀取指定Sheet頁的數據 */ public static List<Map<String,String>> readExcel3(File file, int sheetIndex) throws Exception { try (FileInputStream fs = new FileInputStream(file)) { XSSFWorkbook hw = new XSSFWorkbook(fs); XSSFSheet sheet = hw.getSheetAt(sheetIndex); ArrayList<Map<String,String>> list = new ArrayList<>(); //讀取表頭 List<String> headerList = new ArrayList<String>(); XSSFRow headerRow = sheet.getRow(0); for (int j = 0; j < headerRow.getLastCellNum(); j++) { String val = getCellValue(headerRow,headerRow.getCell(j)); //數據為空 if (StringUtils.isEmpty(val)) { continue; } headerList.add(val); } //讀取數據 for (int i = 1; i < sheet.getPhysicalNumberOfRows(); i++) { XSSFRow dataRow = sheet.getRow(i); if (dataRow == null) { continue; } HashMap<String, String> map = new HashMap<>(); for (int j = 0; j < headerList.size(); j++) { String header = headerList.get(j); String val = getCellValue(dataRow,dataRow.getCell(j)); map.put(header, val); } list.add(map); } return list; } } /** * 獲取單元格內容 */ private static String getCellValue(XSSFRow dataRow, Cell cell){ String cellvalue = ""; if (cell!=null) { switch (cell.getCellType()) { case BOOLEAN: cellvalue = String.valueOf(cell.getBooleanCellValue()); break; case NUMERIC: cellvalue = String.valueOf(cell.getNumericCellValue()).split("\\.")[0]; if(cellvalue.toLowerCase().contains("e")){ cellvalue = new DecimalFormat("#").format(cell.getNumericCellValue()); if(cellvalue.toLowerCase().contains("e")){ throw new RuntimeException(dataRow.getCell(4) + "/數值帶E!!!"); } } break; case STRING: cellvalue = cell.getStringCellValue(); break; case BLANK: break; case ERROR: cellvalue = String.valueOf(cell.getErrorCellValue()); break; case FORMULA: try { cellvalue = String.valueOf(cell.getNumericCellValue()); } catch (IllegalStateException e) { if (e.getMessage().contains("from a STRING cell")) { try { cellvalue = String.valueOf(cell.getStringCellValue()); } catch (IllegalStateException e2) { throw new RuntimeException("公式計算出錯"); } } } break; default: cellvalue = String.valueOf(cell.getBooleanCellValue()); break; } } return cellvalue; } /** * 只支持一級表頭 * * @param file 文件 * @param titleName 表標題 * @param columnNames 列名集合,key是用來設置填充數據時對應單元格的值,label就是對應的列名,生成Excel表時, * 第一維數組下標0對應值為Excel表最左邊的列的列名 例:{ { key,label },{ key,label } } * @param dataLists 數據集合,key對應的是列名集合的key,value是要填充到單元格的值 例:ArrayList<HashMap<String key, String vaule>> */ public static String createExcelFile(File file,String titleName, String[][] columnNames, ArrayList<HashMap<String, String>> dataLists) { //創建HSSFWorkbook對象(excel的文檔對象) HSSFWorkbook wb = new HSSFWorkbook(); //建立新的sheet對象(excel的表單) HSSFSheet sheet = wb.createSheet(titleName);//設置表單名 //1、標題名 //創建標題行,參數為行索引(excel的行),可以是0~65535之間的任何一個 HSSFRow row1 = sheet.createRow(0); createCell(row1, 0, titleName); //合並單元格CellRangeAddress構造參數依次表示起始行,截至行,起始列, 截至列 sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, columnNames.length - 1)); //2、列名 //創建列名行 HSSFRow row2 = sheet.createRow(1); for (int i = 0; i < columnNames.length; i++) { //單元格寬度 sheet.setColumnWidth(i, 20 * 256); createCell(row2, i, columnNames[i][1]);//例:[[key,label],[key,label]] 取label } //3、填充數據 int index = 2;//標題行、列名行,所以數據行默認從第三行開始 for (HashMap<String, String> map : dataLists) { //創建內容行 HSSFRow row3 = sheet.createRow(index); for (int i = 0; i < columnNames.length; i++) { String val = map.get(columnNames[i][0]); createCell(row3, i, val == null ? "" : val);//例:[[key,label],[key,label]] 取key } index++; } try(FileOutputStream outputStream = new FileOutputStream(file)) { wb.write(outputStream); } catch (IOException e) { e.printStackTrace(); } return file.getName()+" 創建成功"; } /** * 創建一個單元格 */ private static void createCell(Row row, int column, String text) { Cell cell = row.createCell(column); // 創建單元格 cell.setCellValue(text); // 設置值 } }
WordUtil,POI操作Word工具類
import org.apache.poi.xwpf.usermodel.*; import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; import java.math.BigInteger; import java.util.List; import java.util.Map; /** * POI操作Word工具類 */ public class WordUtil { /** * 簡單表格生成 * @param xdoc XWPFDocument對象 * @param titles 表頭表頭 * @param values 表內容 */ public static void createSimpleTable(XWPFDocument xdoc,String[] titles,List<Map<String, String>> values){ //行高 int rowHeight = 300; //開始創建表格(默認有一行一列) XWPFTable xTable = xdoc.createTable(); CTTbl ctTbl = xTable.getCTTbl(); CTTblPr tblPr = ctTbl.getTblPr() == null ? ctTbl.addNewTblPr() : ctTbl.getTblPr(); CTTblWidth tblWidth = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW(); tblWidth.setType(STTblWidth.DXA); tblWidth.setW(new BigInteger("8600"));//表格寬度 // 創建表頭數據 XWPFTableRow titleRow = xTable.getRow(0); titleRow.setHeight(rowHeight); for (int i = 0; i < titles.length; i++) { setCellText(i == 0 ? titleRow.getCell(0) :titleRow.createCell(), titles[i]); } // 創建表格內容 for (int i = 0; i < values.size(); i++) { Map<String, String> stringStringMap = values.get(i); //設置列內容 XWPFTableRow row = xTable.insertNewTableRow(i + 1); row.setHeight(rowHeight); for (String title : titles) { setCellText(row.createCell(), stringStringMap.get(title)); } } } /** * 設置列內容 */ private static void setCellText(XWPFTableCell cell,String text) { CTTc cttc = cell.getCTTc(); CTTcPr cellPr = cttc.addNewTcPr(); cellPr.addNewTcW().setW(new BigInteger("2100")); cell.setColor("FFFFFF"); cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); CTTcPr ctPr = cttc.addNewTcPr(); ctPr.addNewVAlign().setVal(STVerticalJc.CENTER); cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER); cell.setText(text); } }
首先寫sql腳本,查出所有表結構信息(表名稱、表注釋、表字段數據等)
-- mysql查詢表名、表注釋、表字段數據 SELECT t.table_name AS '表名稱', t.table_comment AS '表注釋', c.column_name AS '字段名稱', c.column_type AS '數據類型', c.column_comment AS '字段注釋', c.column_key AS '是否主鍵', c.is_nullable AS '是否允許NULL' FROM information_schema.COLUMNS c JOIN information_schema.TABLES t ON c.table_name = t.table_name WHERE c.table_schema = ( SELECT DATABASE ());
把結果集拷貝到Excel中
前期工作准備完畢,接下來開始干正事
import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import java.io.File; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class Test { private static void tables(){ try { XWPFDocument xdoc = new XWPFDocument(); HashMap<String, List<Map<String, String>>> hashMap = new HashMap<>(); //獲取數據 /* -- mysql查詢表名、表注釋、表字段數據 SELECT t.table_name AS '表名稱', t.table_comment AS '表注釋', c.column_name AS '字段名稱', c.column_type AS '數據類型', c.column_comment AS '字段注釋', c.column_key AS '是否主鍵', c.is_nullable AS '是否允許NULL' FROM information_schema.COLUMNS c JOIN information_schema.TABLES t ON c.table_name = t.table_name WHERE c.table_schema = ( SELECT DATABASE ()); */ File file = new File("E:\\TestExcel01.xlsx"); List<Map<String, String>> list = ExcelUtil.readExcel3(file, 0); //處理數據,調整成下面的格式 /* [ {"表名稱":[ {},//一條條字段信息 {},//一條條字段信息 {},//一條條字段信息 ]} ] */ ArrayList<Map<String, String>> arrayList = new ArrayList<>(); String tableName = ""; for (int i = 0; i < list.size(); i++) { Map<String, String> map = list.get(i); String tName = String.valueOf(map.get("表名稱")); if(tableName.equals(tName)){ arrayList.add(map); }else{ hashMap.put(tableName,arrayList); tableName = tName; arrayList = new ArrayList<>(); arrayList.add(map); } if(list.size() - i == 1){ hashMap.put(tableName,arrayList); } } //生成內容 for (String tName : hashMap.keySet()) { if("".equals(tName)){ continue; } List<Map<String, String>> maps = hashMap.get(tName); String tZs = String.valueOf(maps.get(0).get("表注釋")); //設置文字,對表格進行描述 XWPFParagraph xp = xdoc.createParagraph(); xp.setSpacingBefore(0); XWPFRun r1 = xp.createRun(); r1.setFontFamily("宋體"); r1.setFontSize(12); r1.setTextPosition(0); r1.addBreak(); // 換行 r1.setText("表名稱:"+tName); r1.addBreak(); // 換行 r1.setText("表注釋:"+tZs); //表格標題 String[] titles = { "字段名稱", "字段類型", "字段注釋", "允許空值", }; //表格內容 List<Map<String, String>> values = new ArrayList<>(); for (Map<String, String> stringStringMap : maps) { String cName = stringStringMap.get("字段名稱"); String cType = stringStringMap.get("數據類型"); String cZs = stringStringMap.get("字段注釋"); String isPri = stringStringMap.get("是否主鍵"); String isNull = stringStringMap.get("是否允許NULL"); //按照表格標題格式進行封裝 HashMap<String, String> stringStringHashMap = new HashMap<>(); stringStringHashMap.put("字段名稱",cName); stringStringHashMap.put("字段類型",cType); stringStringHashMap.put("字段注釋",cZs); stringStringHashMap.put("允許空值",isNull); values.add(stringStringHashMap); } WordUtil.createSimpleTable(xdoc, titles, values); } //保存word文件 FileOutputStream fos = new FileOutputStream("E:\\Test1.doc"); xdoc.write(fos); fos.close(); System.out.println("操作完成!"); }catch (Exception e){ e.printStackTrace(); } } public static void main(String[] args) { tables(); } }
運行main進行測試
public static void main(String[] args) { tables(); }
效果
后記
通過使用POI,批量生成表格,方便快捷、省心高效,項目經理用了都說好!