package ${basePackage}.frame.excel; import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFComment; import org.apache.poi.xssf.usermodel.XSSFDrawing; import org.apache.poi.xssf.usermodel.XSSFRichTextString; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import ${basePackage}.frame.excel.annotation.ColumnDescription; import ${basePackage}.frame.excel.annotation.ColumnName; import ${basePackage}.frame.excel.annotation.Ignore; import ${basePackage}.frame.excel.annotation.ParentFirst; import ${basePackage}.frame.excel.annotation.SheetName; import ${basePackage}.frame.excel.converter.BooleanConverter; import ${basePackage}.frame.excel.converter.ByteConverter; import ${basePackage}.frame.excel.converter.CharacterConverter; import ${basePackage}.frame.excel.converter.Converter; import ${basePackage}.frame.excel.converter.DateConverter; import ${basePackage}.frame.excel.converter.DoubleConverter; import ${basePackage}.frame.excel.converter.FloatConverter; import ${basePackage}.frame.excel.converter.IntegerConverter; import ${basePackage}.frame.excel.converter.LongConverter; import ${basePackage}.frame.excel.converter.ShortConverter; import ${basePackage}.frame.excel.converter.StringConverter; import ${basePackage}.frame.excel.exception.ReadErrorException; import ${basePackage}.frame.excel.exception.TemplateNotMatchException; import ${basePackage}.frame.excel.exception.ValueConverterException; import ${basePackage}.frame.excel.style.DataCellStyle; import ${basePackage}.frame.excel.style.ErrorCellStyle; import ${basePackage}.frame.excel.style.HeadCellStyle; import ${basePackage}.frame.excel.style.RedFont; import ${basePackage}.frame.excel.style.SuccessCellStyle; import ${basePackage}.frame.utils.ClassUtil; import ${basePackage}.frame.utils.FileUtil; import ${basePackage}.frame.utils.LogUtil; import ${basePackage}.frame.utils.ValidationUtil; import ${basePackage}.module.system.ent.Dept; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * WExcel - Excel-Sheet对象,完整的数据集合对象。 * * @author wangbing * @version 0.0.1 * @since 2017-01-01 */ public class WExcel implements Serializable, Cloneable { /** * 表名 */ private String name; /** * 是否冻结第一行 */ private boolean freezeFirst; /** * 模板类 */ private Class templateClass; /** * 表头的集合 */ private List columnList = new ArrayList<>(); /** * 单元格里存放的对象 */ private List rowList = new ArrayList<>(); /** * 根据输入的模板类打印下载模板。 */ public WExcel(Class tClass) { this.templateClass = tClass; initColumns(tClass); } /** * 根据模板类对DataTable添加相应的列。 * * @return WColumn集合 */ private List initColumns(Class clazz) { //获取工作簿名称,没有则以类名为默认工作簿名称 if (clazz.isAnnotationPresent(SheetName.class)) { SheetName sheetName = clazz.getAnnotation(SheetName.class); this.setName(sheetName.value()); this.setFreezeFirst(sheetName.freezeFirst()); } else { this.setName(clazz.getSimpleName()); } //是否关注父类属性 boolean parentFirst = clazz.isAnnotationPresent(ParentFirst.class) && clazz.getAnnotation(ParentFirst.class).value(); Field[] fields = ClassUtil.getFields(clazz, parentFirst); for (Field field : fields) { if (field.isAnnotationPresent(Ignore.class) && field.getAnnotation(Ignore.class).value()) { continue; } WColumn WColumn = new WColumn(); WColumn.setField(field); Method set = ClassUtil.setMethod(field.getName(), clazz, field.getType()); WColumn.setSetMethod(set); Method get = ClassUtil.getMethod(field.getName(), clazz); WColumn.setGetMethod(get); //获取列名称 if (!field.isAnnotationPresent(ColumnName.class)) { WColumn.setName(field.getName()); } else { ColumnName columnColumnName = field.getAnnotation(ColumnName.class); WColumn.setName(columnColumnName.value()); WColumn.setCellWidth(columnColumnName.width()); WColumn.setRequired(columnColumnName.required()); } //获取列填写说明或描述 if (field.isAnnotationPresent(ColumnDescription.class)) { WColumn.setDescription(field.getAnnotation(ColumnDescription.class).value()); } //获取列类型 if (field.isAnnotationPresent(${basePackage}.frame.excel.annotation.Converter.class)) { ${basePackage}.frame.excel.annotation.Converter converter = field.getAnnotation(${basePackage}.frame.excel.annotation.Converter.class); Class target = converter.target(); try { WColumn.setConverter((Converter) target.newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } else { if (field.getType() == boolean.class || field.getType() == Boolean.class) { WColumn.setConverter(new BooleanConverter()); WColumn.setCellType(Cell.CELL_TYPE_BOOLEAN); } else if (field.getType() == byte.class || field.getType() == Byte.class) { WColumn.setConverter(new ByteConverter()); WColumn.setCellType(Cell.CELL_TYPE_NUMERIC); } else if (field.getType() == char.class || field.getType() == Character.class) { WColumn.setConverter(new CharacterConverter()); WColumn.setCellType(Cell.CELL_TYPE_STRING); } else if (field.getType() == short.class || field.getType() == Short.class) { WColumn.setConverter(new ShortConverter()); WColumn.setCellType(Cell.CELL_TYPE_NUMERIC); } else if (field.getType() == int.class || field.getType() == Integer.class) { WColumn.setConverter(new IntegerConverter()); WColumn.setCellType(Cell.CELL_TYPE_NUMERIC); } else if (field.getType() == long.class || field.getType() == Long.class) { WColumn.setConverter(new LongConverter()); WColumn.setCellType(Cell.CELL_TYPE_NUMERIC); } else if (field.getType() == float.class || field.getType() == Float.class) { WColumn.setConverter(new FloatConverter()); WColumn.setCellType(Cell.CELL_TYPE_NUMERIC); } else if (field.getType() == double.class || field.getType() == Double.class) { WColumn.setConverter(new DoubleConverter()); WColumn.setCellType(Cell.CELL_TYPE_NUMERIC); } else if (field.getType() == Date.class) { WColumn.setConverter(new DateConverter()); WColumn.setCellType(Cell.CELL_TYPE_NUMERIC); } else if (field.getType() == String.class) { WColumn.setConverter(new StringConverter()); WColumn.setCellType(Cell.CELL_TYPE_STRING); } else { throw new RuntimeException("Can not find Converter"); } } columnList.add(WColumn); } return columnList; } public WExcel loadData(List list) { return loadData(list, null); } /** * 此构造方法仅用于转换对象列表。
* 并不会对数据的格式和合法性进行检验。 * * @param list 需要导出的对象列表 */ public WExcel loadData(List list, Processor processor) { if (list.size() > 0) { for (T t : list) { WRow row = new WRow(); for (WColumn column : columnList) { if (column == null) { continue; } Method method = column.getGetMethod(); try { Object value = method.invoke(t); if (null == value) { row.put(column.getName(), new WCell()); } else { String string = column.getConverter().string(value); row.put(column.getName(), new WCell(string)); } } catch (IllegalAccessException e) { LogUtil.w("can not invoke get method!"); } catch (InvocationTargetException e) { LogUtil.w(method.getName() + " unexpected exception!"); } // <2层检查>检查模板注解验证是否通过 row.addErrors(ValidationUtil.validate(t)); // <3层检查>如果没有错误,则可以执行处理器进行逻辑处理 if (!row.hasError() && processor != null) { row.addErrors(processor.exec(t)); } } this.rowList.add(row); } } return this; } public WExcel loadData(byte[] bytes) throws TemplateNotMatchException, ReadErrorException { return loadData(bytes, null); } /** * 以Excel文件的字节数组为数据源,为自己赋值的同时,与指定的模板类进行数据校验。
* 如果匹配过程中发现了不符合的数据,会在对应的单元中添加错误信息。
*/ public WExcel loadData(byte[] bytes, Processor processor) throws TemplateNotMatchException, ReadErrorException { Workbook workbook = null; InputStream is = null; boolean flag; try { flag = true; is = new ByteArrayInputStream(bytes); //读取文件流 workbook = new HSSFWorkbook(is); } catch (Exception e) { flag = false; } if (!flag) { try { flag = true; is = new ByteArrayInputStream(bytes); //读取文件流 workbook = new XSSFWorkbook(is); } catch (Exception e) { flag = false; } } if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if (!flag) { throw new ReadErrorException("读取Excel文件错误"); } //第一张Sheet表 Sheet sheet = workbook.getSheetAt(0); //获取Sheet名称 if (templateClass.isAnnotationPresent(SheetName.class)) {//如果模板存在注解则使用注解名称 SheetName sheetName = templateClass.getAnnotation(SheetName.class); this.setName(sheetName.value()); } else {//将类名设为表名,如果类名不存在,将Excel表名设为表名 this.setName(sheet.getSheetName()); } //读取表头 Row headRow = sheet.getRow(0); //获取Excel列的总数 int columnSum = headRow.getPhysicalNumberOfCells(); //检查列数量 if (columnList.size() != columnSum) { throw new TemplateNotMatchException("与模板列数量不同。"); } else { for (int i = 0; i < columnList.size(); i++) { WColumn wColumn = columnList.get(i); Cell cell = headRow.getCell(i); String headValue = getValue(cell); headValue = headValue.replace("*", ""); headValue = headValue.replace(" ", ""); if (!wColumn.getName().equals(headValue)) { throw new TemplateNotMatchException("第" + (i + 1) + "项,不匹配的列名," + wColumn.getName() + "和" + headValue); } } } int maxRowNumber = sheet.getLastRowNum(); //Excel文件的总行数 // 逐行读取导入文件的数据 for (int i = 0; i < maxRowNumber; i++) { Row inputRow = sheet.getRow(i + 1); //Excel中的一行数据,第0行为表头,所以要加1 WRow row = new WRow(); rowList.add(row); if (null != inputRow) { for (int j = 0; j < columnList.size(); j++) { WColumn wcolumn = columnList.get(j); /* 取得当前格子的值 */ Cell excelCell = inputRow.getCell(j); WCell WCell = new WCell(); row.put(wcolumn.getName(), WCell); String value = ""; if (null != excelCell) { value = getValue(excelCell); } value = value.trim(); WCell.setValue(value); } } try { T t = templateClass.newInstance(); // <1层检查>检查数据格式是否正确 row.addErrors(transferMap(row, t)); // <2层检查>检查模板注解验证是否通过 row.addErrors(ValidationUtil.validate(t)); // <3层检查>如果没有错误,则可以执行处理器进行逻辑处理 if (!row.hasError() && processor != null) { row.addErrors(processor.exec(t)); } } catch (InstantiationException | IllegalAccessException e) { row.addError("模板对象默认构造函数错误"); } } return this; } /** * 转换某行为一个对象 * * @param row 行对象 * @param target 模板对象 * @return 模板对象 */ public List transferMap(WRow row, T target) { List err = new ArrayList<>(); for (String key : row.keySet()) { for (WColumn column : columnList) { String name = column.getName(); Method setMethod = column.getSetMethod(); if (key.equals(name)) { WCell WCell = row.get(column.getName()); if (null != WCell) { String value = WCell.getValue(); //获取转换器 Converter converter = column.getConverter(); try { setMethod.invoke(target, converter.convert(value)); } catch (ValueConverterException e) { e.printStackTrace(); err.add(e.getMessage()); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); err.add("[" + setMethod.getName() + "]执行错误"); } } break; } } } return err; } /** * 获取表名 * * @return 表名 */ public String getName() { return name; } /** * 设置表名 * * @param name 表名 */ public void setName(String name) { this.name = name; } public boolean getFreezeFirst() { return freezeFirst; } public void setFreezeFirst(boolean freezeFirst) { this.freezeFirst = freezeFirst; } public final String toCSV() { StringBuilder sb = new StringBuilder(); for (WColumn WColumn : this.columnList) { if (WColumn != null) { sb.append(WColumn.getName()).append(","); } } sb.append("\n"); for (int i = 0; i < this.rowList.size(); i++) { for (int j = 0; j < this.columnList.size(); j++) { WColumn wColumn = this.columnList.get(j); WCell wCell = this.rowList.get(i).get(wColumn.getName()); sb.append(wCell.getValue()).append(","); } sb.append("\n"); } return sb.toString(); } /** * 判断DataTable是否包含错误信息 * * @return 是否包含错误. */ public final boolean hasError() { for (WRow wRow : rowList) { if (wRow.hasError()) { return true; } } return false; } public byte[] getBytes() { XSSFWorkbook workbook = getExcel(); if (workbook != null) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { workbook.write(outputStream); } catch (IOException e) { return null; } return outputStream.toByteArray(); } return null; } public XSSFWorkbook getExcel() { XSSFWorkbook workbook = new XSSFWorkbook(); //创建一个Sheet表 XSSFSheet sheet = workbook.createSheet(name); sheet.setDefaultRowHeightInPoints(18); Row firstRow = sheet.createRow(0); // 下标为0的行开始 XSSFDrawing drawing = sheet.createDrawingPatriarch(); int offset = 0; // 添加结果和错误说明列 if (hasError()) { offset++; {// 第一栏结果栏 Cell firstCell = firstRow.createCell(0); firstCell.setCellStyle(new HeadCellStyle(workbook).getStyle()); firstCell.setCellValue(new XSSFRichTextString("执行结果")); XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6); XSSFComment comment = drawing.createCellComment(anchor); comment.setString("此列为检查结果,导入时请处理完错误,并删除该列!"); firstCell.setCellComment(comment); } offset++; {// 第二栏错误信息栏 Cell secondCell = firstRow.createCell(1); secondCell.setCellStyle(new HeadCellStyle(workbook).getStyle()); secondCell.setCellValue(new XSSFRichTextString("结果说明")); sheet.setColumnWidth(1, 18 * 256); XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6); XSSFComment comment = drawing.createCellComment(anchor); comment.setString("此列为检查结果信息列,导入时请处理完错误,并删除该列!"); secondCell.setCellComment(comment); } } for (int j = 0; j < this.columnList.size(); j++) { WColumn column = this.columnList.get(j); Cell firstCell = firstRow.createCell(j + offset); String columnName = column.getName(); XSSFRichTextString textString; if (column.isRequired()) { textString = new XSSFRichTextString("*" + columnName); textString.applyFont(0, 1, new RedFont(workbook).getFont()); textString.applyFont(1, textString.length(), workbook.createFont()); } else { textString = new XSSFRichTextString(columnName); textString.applyFont(workbook.createFont()); } StringBuilder sb = new StringBuilder(); sb.append(column.getDescription()).append("\n"); // 如果填写了注释信息 if (sb.length() > 1) { XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6); XSSFComment comment = drawing.createCellComment(anchor); comment.setString(sb.toString()); firstCell.setCellComment(comment); } firstCell.setCellValue(textString); firstCell.setCellStyle(new HeadCellStyle(workbook).getStyle()); sheet.setColumnWidth(j + offset, (4 + column.getCellWidth()) * 256); } // 冻结第一行 if (freezeFirst) { sheet.createFreezePane(255, 1); } // 填充数据 for (int i = 0; i < this.rowList.size(); i++) { WRow wRow = this.rowList.get(i); Row row = sheet.createRow(i + 1); if(offset> 0){ if (this.rowList.get(i).hasError()) { // 添加结果 List errorList = wRow.getErrorList(); Cell resultCell = row.createCell(0); resultCell.setCellStyle(new ErrorCellStyle(workbook).getStyle()); resultCell.setCellValue("错误"); // 添加错误信息详细说明 Cell errsCell = row.createCell(1); errsCell.setCellStyle(new ErrorCellStyle(workbook).getStyle()); String join = String.join(";", errorList); errsCell.setCellValue(new XSSFRichTextString(join)); } else { // 添加结果 Cell resultCell = row.createCell(0); resultCell.setCellStyle(new SuccessCellStyle(workbook).getStyle()); resultCell.setCellValue("成功"); // 添加错误信息详细说明 Cell errsCell = row.createCell(1); errsCell.setCellStyle(new SuccessCellStyle(workbook).getStyle()); errsCell.setCellValue(""); } } for (int j = 0; j < this.columnList.size(); j++) { WColumn column = this.columnList.get(j); Cell xssfCell = row.createCell(j + offset); WCell WCell = this.rowList.get(i).get(column.getName()); if (null == WCell) { continue; } String value = WCell.getValue(); xssfCell.setCellType(column.getCellType()); if (column.getCellType() == Cell.CELL_TYPE_NUMERIC || column.getCellType() == Cell.CELL_TYPE_BOOLEAN) { xssfCell.setCellStyle(new DataCellStyle(workbook, CellStyle.ALIGN_RIGHT, wRow.hasError()).getStyle()); } else { xssfCell.setCellStyle(new DataCellStyle(workbook, CellStyle.ALIGN_LEFT, wRow.hasError()).getStyle()); } xssfCell.setCellValue(value); } } return workbook; } /** * 获取单元格的值 * * @param cell 要获取值的单元格 * @return 单元格的值 */ public static String getValue(Cell cell) { if (cell == null) { return ""; } switch (cell.getCellType()) { case Cell.CELL_TYPE_STRING: return cell.getStringCellValue(); case Cell.CELL_TYPE_BOOLEAN: return String.valueOf(cell.getBooleanCellValue()); case Cell.CELL_TYPE_NUMERIC: if (HSSFDateUtil.isCellDateFormatted(cell)) { Date value = cell.getDateCellValue(); return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value); } else { double numericCellValue = cell.getNumericCellValue(); String s = String.valueOf(numericCellValue); return s.replaceAll("\\.0$", ""); } default: return cell.getStringCellValue(); } } public interface Processor { List exec(T t); } public void toFile(File file) throws IOException { File parentFile = file.getParentFile(); if (!parentFile.exists() && !parentFile.mkdirs()) { throw new RuntimeException("路径创建失败"); } if (!file.exists() && !file.createNewFile()) { throw new RuntimeException("文件创建失败"); } FileOutputStream fileOutputStream = new FileOutputStream(file); fileOutputStream.write(getBytes()); fileOutputStream.close(); } public static void main(String[] args) throws IOException { Dept dept = new Dept(); dept.setDeptName("AAAAAA"); ArrayList depts = new ArrayList(); depts.add(dept); File file = new File("E:\\E.xlsx"); // 导出模板 // new WExcel(Dept.class).loadData(depts).toFile(file); // 检查excel文件是否符合导入 byte[] bytes = FileUtil.readFileToByteArray(new File("E:\\E.xlsx")); try { WExcel check = new WExcel(Dept.class).loadData(bytes); check.toFile(new File("E:\\E_err.xlsx")); System.out.println(check.hasError()); } catch (TemplateNotMatchException e) { e.printStackTrace(); } catch (ReadErrorException e) { e.printStackTrace(); } System.out.println(); } }