優(yōu)質(zhì)文章,第一時(shí)間送達(dá) 日常在做后臺(tái)系統(tǒng)的時(shí)候會(huì)很頻繁的遇到Excel導(dǎo)入導(dǎo)出的問(wèn)題,正好這次在做一個(gè)后臺(tái)系統(tǒng),就想著寫一個(gè)公用工具來(lái)進(jìn)行Excel的導(dǎo)入導(dǎo)出。 一般我們?cè)趯?dǎo)出的時(shí)候都是導(dǎo)出的前端表格,而前端表格同時(shí)也會(huì)對(duì)應(yīng)的在后臺(tái)有一個(gè)映射類。 所以在寫這個(gè)工具的時(shí)候我們先理一下我們需要實(shí)現(xiàn)的效果: 導(dǎo)出方法接收一個(gè)list集合,和一個(gè)Class類型,和HttpServletResponse 對(duì)象 導(dǎo)出是可能會(huì)有下拉列表,所以需要一個(gè)map存儲(chǔ)下拉列表數(shù)據(jù)源,傳入?yún)?shù)后只需一行代碼即可導(dǎo)出 導(dǎo)入方法需要傳入file文件,以及一個(gè)Class類型,導(dǎo)入之后將會(huì)返回一個(gè)list集合,里面的對(duì)象就是傳入類型的對(duì)象,傳入?yún)?shù)后只需一行代碼即可導(dǎo)入
實(shí)現(xiàn)過(guò)程: 首先需要?jiǎng)?chuàng)建三個(gè)注解 一個(gè)是EnableExport ,必須有這個(gè)注解才能導(dǎo)出 /** * 設(shè)置允許導(dǎo)出 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface EnableExport { String fileName();
}
然后就是EnableExportField,有這個(gè)注解的字段才會(huì)導(dǎo)出到Excel里面,并且可以設(shè)置列寬 /** * 設(shè)置該字段允許導(dǎo)出 * 并且可以設(shè)置寬度 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface EnableExportField { int colWidth() default 100; String colName(); }
再就是ImportIndex,導(dǎo)入的時(shí)候設(shè)置Excel中的列對(duì)應(yīng)的序號(hào) /** * 導(dǎo)入時(shí)索引 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ImportIndex { int index() ;
}
注解使用示例
 三個(gè)注解創(chuàng)建好之后就需要開始操作Excel了 首先,導(dǎo)入方法。在后臺(tái)接收到前端上傳的Excel文件之后,使用poi來(lái)讀取Excel文件 我們根據(jù)傳入的類型上面的字段注解的順序來(lái)分別為不同的字段賦值,然后存入集合中,再返回 代碼如下: /** * 將Excel轉(zhuǎn)換為對(duì)象集合 * @param excel Excel 文件 * @param clazz pojo類型 * @return */ public static List<Object> parseExcelToList(File excel,Class clazz){ List<Object> res = new ArrayList<>(); // 創(chuàng)建輸入流,讀取Excel InputStream is = null; Sheet sheet = null; try { is = new FileInputStream(excel.getAbsolutePath()); if (is != null) { Workbook workbook = WorkbookFactory.create(is); //默認(rèn)只獲取第一個(gè)工作表 sheet = workbook.getSheetAt(0); if (sheet != null) { //前兩行是標(biāo)題 int i = 2; String values[] ; Row row = sheet.getRow(i); while (row != null) { //獲取單元格數(shù)目 int cellNum = row.getPhysicalNumberOfCells(); values = new String[cellNum]; for (int j = 0; j <= cellNum; j++) { Cell cell = row.getCell(j); if (cell != null) { //設(shè)置單元格內(nèi)容類型 cell.setCellType(Cell.CELL_TYPE_STRING ); //獲取單元格值 String value = cell.getStringCellValue() == null ? null : cell.getStringCellValue(); values[j]=value; } } Field[] fields = clazz.getDeclaredFields(); Object obj = clazz.newInstance(); for(Field f : fields){ if(f.isAnnotationPresent(ImportIndex.class)){ ImportIndex annotation = f.getDeclaredAnnotation(ImportIndex.class); int index = annotation.index(); f.setAccessible(true); //此處使用了阿里巴巴的fastjson包里面的一個(gè)類型轉(zhuǎn)換工具類 Object val =TypeUtils.cast(values[index],f.getType(),null); f.set(obj,val); } } res.add(obj); i++; row=sheet.getRow(i); }
} } } catch (Exception e) { e.printStackTrace(); } return res; }
接下來(lái)就是導(dǎo)出方法 導(dǎo)出分為幾個(gè)步驟: 建立一個(gè)工作簿,也就是類型新建一個(gè)Excel文件
 建立一張sheet表
 設(shè)置標(biāo)的行高和列寬
 繪制標(biāo)題和表頭
 這兩個(gè)方法是自定義方法,代碼會(huì)貼在后面 寫入數(shù)據(jù)到Excel
 創(chuàng)建下拉列表
 寫入文件到response
 到這里導(dǎo)出工作就完成了 下面是一些自定義方法的代碼
/** * 獲取一個(gè)基本的帶邊框的單元格 * @param workbook * @return */ private static HSSFCellStyle getBasicCellStyle(HSSFWorkbook workbook){ HSSFCellStyle hssfcellstyle = workbook.createCellStyle(); hssfcellstyle.setBorderLeft(HSSFCellStyle.BORDER_THIN); hssfcellstyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); hssfcellstyle.setBorderRight(HSSFCellStyle.BORDER_THIN); hssfcellstyle.setBorderTop(HSSFCellStyle.BORDER_THIN); hssfcellstyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); hssfcellstyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); hssfcellstyle.setWrapText(true); return hssfcellstyle; }
/** * 獲取帶有背景色的標(biāo)題單元格 * @param workbook * @return */ private static HSSFCellStyle getTitleCellStyle(HSSFWorkbook workbook){ HSSFCellStyle hssfcellstyle = getBasicCellStyle(workbook); hssfcellstyle.setFillForegroundColor((short) HSSFColor.CORNFLOWER_BLUE.index); // 設(shè)置背景色 hssfcellstyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); return hssfcellstyle; }
/** * 創(chuàng)建一個(gè)跨列的標(biāo)題行 * @param workbook * @param hssfRow * @param hssfcell * @param hssfsheet * @param allColNum * @param title */ private static void createTitle(HSSFWorkbook workbook, HSSFRow hssfRow , HSSFCell hssfcell, HSSFSheet hssfsheet,int allColNum,String title){ //在sheet里增加合并單元格 CellRangeAddress cra = new CellRangeAddress(0, 0, 0, allColNum); hssfsheet.addMergedRegion(cra); // 使用RegionUtil類為合并后的單元格添加邊框 RegionUtil.setBorderBottom(1, cra, hssfsheet, workbook); // 下邊框 RegionUtil.setBorderLeft(1, cra, hssfsheet, workbook); // 左邊框 RegionUtil.setBorderRight(1, cra, hssfsheet, workbook); // 有邊框 RegionUtil.setBorderTop(1, cra, hssfsheet, workbook); // 上邊框
//設(shè)置表頭 hssfRow = hssfsheet.getRow(0); hssfcell = hssfRow.getCell(0); hssfcell.setCellStyle( getTitleCellStyle(workbook)); hssfcell.setCellType(HSSFCell.CELL_TYPE_STRING); hssfcell.setCellValue(title); }
/** * 設(shè)置表頭標(biāo)題欄以及表格高度 * @param workbook * @param hssfRow * @param hssfcell * @param hssfsheet * @param colNames */ private static void createHeadRow(HSSFWorkbook workbook,HSSFRow hssfRow , HSSFCell hssfcell,HSSFSheet hssfsheet,List<String> colNames){ //插入標(biāo)題行 hssfRow = hssfsheet.createRow(1); for (int i = 0; i < colNames.size(); i++) { hssfcell = hssfRow.createCell(i); hssfcell.setCellStyle(getTitleCellStyle(workbook)); hssfcell.setCellType(HSSFCell.CELL_TYPE_STRING); hssfcell.setCellValue(colNames.get(i)); } } /** * excel添加下拉數(shù)據(jù)校驗(yàn) * @param sheet 哪個(gè) sheet 頁(yè)添加校驗(yàn) * @return */ public static void createDataValidation(Sheet sheet,Map<Integer,String[]> selectListMap) { if(selectListMap!=null) { selectListMap.forEach( // 第幾列校驗(yàn)(0開始)key 數(shù)據(jù)源數(shù)組value (key, value) -> { if(value.length>0) { CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(2, 65535, key, key); DataValidationHelper helper = sheet.getDataValidationHelper(); DataValidationConstraint constraint = helper.createExplicitListConstraint(value); DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList); //處理Excel兼容性問(wèn)題 if (dataValidation instanceof XSSFDataValidation) { dataValidation.setSuppressDropDownArrow(true); dataValidation.setShowErrorBox(true); } else { dataValidation.setSuppressDropDownArrow(false); } dataValidation.setEmptyCellAllowed(true); dataValidation.setShowPromptBox(true); dataValidation.createPromptBox('提示', '只能選擇下拉框里面的數(shù)據(jù)'); sheet.addValidationData(dataValidation); } } ); } }
使用實(shí)例 導(dǎo)出數(shù)據(jù)
 導(dǎo)入數(shù)據(jù)(返回對(duì)象List)
 作者 | _JenKin 來(lái)源 | csdn.net/youzi1394046585/article/details/86670203
|