diff --git a/common/src/main/java/com/jeesite/common/text/DiffMatchPatchTest.java b/common/src/main/java/com/jeesite/common/text/DiffMatchPatchTest.java index 57baafed..48655ac1 100644 --- a/common/src/main/java/com/jeesite/common/text/DiffMatchPatchTest.java +++ b/common/src/main/java/com/jeesite/common/text/DiffMatchPatchTest.java @@ -25,14 +25,13 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import org.junit.Assert; + import com.jeesite.common.io.FileUtils; import com.jeesite.common.text.DiffMatchPatch.Diff; import com.jeesite.common.text.DiffMatchPatch.LinesToCharsResult; import com.jeesite.common.text.DiffMatchPatch.Patch; -import junit.framework.Assert; - -@SuppressWarnings("deprecation") public class DiffMatchPatchTest { private DiffMatchPatch dmp; diff --git a/common/src/main/java/com/jeesite/common/utils/excel/ExcelExport.java b/common/src/main/java/com/jeesite/common/utils/excel/ExcelExport.java index 12cb0242..007f37fe 100644 --- a/common/src/main/java/com/jeesite/common/utils/excel/ExcelExport.java +++ b/common/src/main/java/com/jeesite/common/utils/excel/ExcelExport.java @@ -1,564 +1,609 @@ -/** - * Copyright (c) 2013-Now http://jeesite.com All rights reserved. - */ -package com.jeesite.common.utils.excel; - -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang3.StringUtils; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.Comment; -import org.apache.poi.ss.usermodel.Font; -import org.apache.poi.ss.usermodel.IndexedColors; -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.ss.util.CellRangeAddress; -import org.apache.poi.xssf.streaming.SXSSFWorkbook; -import org.apache.poi.xssf.usermodel.XSSFClientAnchor; -import org.apache.poi.xssf.usermodel.XSSFRichTextString; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.annotation.JsonFormat; -import com.jeesite.common.codec.EncodeUtils; -import com.jeesite.common.collect.ListUtils; -import com.jeesite.common.reflect.ReflectUtils; -import com.jeesite.common.utils.excel.annotation.ExcelField; -import com.jeesite.common.utils.excel.annotation.ExcelField.Align; -import com.jeesite.common.utils.excel.annotation.ExcelFields; -import com.jeesite.common.utils.excel.annotation.ExcelField.Type; - -/** - * 导出Excel文件(导出“XLSX”格式,支持大数据量导出 @see org.apache.poi.ss.SpreadsheetVersion) - * @author ThinkGem - * @version 2013-04-21 - */ -public class ExcelExport { - - private static Logger log = LoggerFactory.getLogger(ExcelExport.class); - - /** - * 工作薄对象 - */ - private Workbook wb; - - /** - * 工作表对象 - */ - private Sheet sheet; - - /** - * 样式列表 - */ - private Map styles; - - /** - * 当前行号 - */ - private int rownum; - - /** - * 注解列表(Object[]{ ExcelField, Field/Method }) - */ - List annotationList = ListUtils.newArrayList(); - - /** - * 构造函数 - * @param title 表格标题,传“空值”,表示无标题 - * @param cls 实体对象,通过annotation.ExportField获取标题 - */ - public ExcelExport(String title, Class cls){ - this(title, cls, Type.EXPORT); - } - - /** - * 构造函数 - * @param title 表格标题,传“空值”,表示无标题 - * @param cls 实体对象,通过annotation.ExportField获取标题 - * @param type 导出类型(1:导出数据;2:导出模板) - * @param groups 导入分组 - */ - public ExcelExport(String title, Class cls, Type type, String... groups){ - this(null, null, title, cls, type, groups); - } - - /** - * 构造函数 - * @param wb 工作簿对象,支持多个Sheet,通过ExcelExport.createWorkbook()创建 - * @param sheetName,指定Sheet名称 - * @param title 表格标题,传“空值”,表示无标题 - * @param cls 实体对象,通过annotation.ExportField获取标题 - * @param type 导出类型(1:导出数据;2:导出模板) - * @param groups 导入分组 - */ - public ExcelExport(Workbook wb, String sheetName, String title, Class cls, Type type, String... groups){ - // Get annotation field - Field[] fs = cls.getDeclaredFields(); - for (Field f : fs){ - ExcelFields efs = f.getAnnotation(ExcelFields.class); - if (efs != null && efs.value() != null){ - for (ExcelField ef : efs.value()){ - addAnnotation(annotationList, ef, f, type, groups); - } - } - ExcelField ef = f.getAnnotation(ExcelField.class); - addAnnotation(annotationList, ef, f, type, groups); - } - // Get annotation method - Method[] ms = cls.getDeclaredMethods(); - for (Method m : ms){ - ExcelFields efs = m.getAnnotation(ExcelFields.class); - if (efs != null && efs.value() != null){ - for (ExcelField ef : efs.value()){ - addAnnotation(annotationList, ef, m, type, groups); - } - } - ExcelField ef = m.getAnnotation(ExcelField.class); - addAnnotation(annotationList, ef, m, type, groups); - } - // Field sorting - Collections.sort(annotationList, new Comparator() { - @Override - public int compare(Object[] o1, Object[] o2) { - return new Integer(((ExcelField)o1[0]).sort()).compareTo( - new Integer(((ExcelField)o2[0]).sort())); - }; - }); - // Initialize - List headerList = ListUtils.newArrayList(); - List headerWidthList = ListUtils.newArrayList(); - for (Object[] os : annotationList){ - ExcelField ef = (ExcelField)os[0]; - String headerTitle = ef.title(); - // 如果是导出,则去掉注释 - if (type == Type.EXPORT){ - String[] ss = StringUtils.split(headerTitle, "**", 2); - if (ss.length == 2){ - headerTitle = ss[0]; - } - } - headerList.add(headerTitle); - headerWidthList.add(ef.width()); - } - initialize(wb, sheetName, title, headerList, headerWidthList); - } - - /** - * 构造函数 - * @param title 表格标题,传“空值”,表示无标题 - * @param headers 表头数组 - */ - public ExcelExport(String title, List headerList) { - this(null, null, title, headerList); - } - - /** - * 构造函数 - * @param wb 工作簿对象,支持多个Sheet,通过ExcelExport.createWorkbook()创建 - * @param sheetName,指定Sheet名称 - * @param title 表格标题,传“空值”,表示无标题 - * @param headerList 表头列表 - */ - public ExcelExport(Workbook wb, String sheetName, String title, List headerList) { - initialize(wb, sheetName, title, headerList, null); - } - - /** - * 创建一个工作簿 - */ - public static Workbook createWorkbook(){ - return new SXSSFWorkbook(500); - } - - /** - * 添加到 annotationList - */ - private void addAnnotation(List annotationList, ExcelField ef, Object fOrM, Type type, String... groups){ -// if (ef != null && (ef.type()==0 || ef.type()==type)){ - if (ef != null && (ef.type() == Type.ALL || ef.type() == type)){ - if (groups != null && groups.length > 0){ - boolean inGroup = false; - for (String g : groups){ - if (inGroup){ - break; - } - for (String efg : ef.groups()){ - if (StringUtils.equals(g, efg)){ - inGroup = true; - annotationList.add(new Object[]{ef, fOrM}); - break; - } - } - } - }else{ - annotationList.add(new Object[]{ef, fOrM}); - } - } - } - - /** - * 初始化函数 - * @param title 表格标题,传“空值”,表示无标题 - * @param headerList 表头列表 - */ - private void initialize(Workbook wb, String sheetName, String title, List headerList, List headerWidth) { - if (wb == null){ - this.wb = createWorkbook(); - } - this.sheet = wb.createSheet(StringUtils.defaultString(sheetName, "Export")); - this.styles = createStyles(wb); - // Create title - if (StringUtils.isNotBlank(title)){ - Row titleRow = sheet.createRow(rownum++); - titleRow.setHeightInPoints(30); - Cell titleCell = titleRow.createCell(0); - titleCell.setCellStyle(styles.get("title")); - titleCell.setCellValue(title); - sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), - titleRow.getRowNum(), titleRow.getRowNum(), headerList.size()-1)); - } - // Create header - if (headerList == null){ - throw new ExcelException("headerList not null!"); - } - Row headerRow = sheet.createRow(rownum++); - headerRow.setHeightInPoints(16); - for (int i = 0; i < headerList.size(); i++) { - Cell cell = headerRow.createCell(i); - cell.setCellStyle(styles.get("header")); - String[] ss = StringUtils.split(headerList.get(i), "**", 2); - if (ss.length==2){ - cell.setCellValue(ss[0]); - Comment comment = this.sheet.createDrawingPatriarch().createCellComment( - new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6)); - comment.setString(new XSSFRichTextString(ss[1])); - cell.setCellComment(comment); - }else{ - cell.setCellValue(headerList.get(i)); - } -// sheet.autoSizeColumn(i); - } - boolean isDefWidth = (headerWidth != null && headerWidth.size() == headerList.size()); - for (int i = 0; i < headerList.size(); i++) { - int colWidth = -1; - if (isDefWidth){ - colWidth = headerWidth.get(i); - } - if (colWidth == -1){ - colWidth = sheet.getColumnWidth(i)*2; - colWidth = colWidth < 3000 ? 3000 : colWidth; - } - if (colWidth == 0){ - sheet.setColumnHidden(i, true); - }else{ - sheet.setColumnWidth(i, colWidth); - } - } - log.debug("Initialize success."); - } - - /** - * 创建表格样式 - * @param wb 工作薄对象 - * @return 样式列表 - */ - private Map createStyles(Workbook wb) { - Map styles = new HashMap(); - - CellStyle style = wb.createCellStyle(); - style.setAlignment(CellStyle.ALIGN_CENTER); - style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); - Font titleFont = wb.createFont(); - titleFont.setFontName("Arial"); - titleFont.setFontHeightInPoints((short) 16); - titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD); - style.setFont(titleFont); - styles.put("title", style); - - style = wb.createCellStyle(); - style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); - style.setBorderRight(CellStyle.BORDER_THIN); - style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setBorderLeft(CellStyle.BORDER_THIN); - style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setBorderTop(CellStyle.BORDER_THIN); - style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setBorderBottom(CellStyle.BORDER_THIN); - style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - Font dataFont = wb.createFont(); - dataFont.setFontName("Arial"); - dataFont.setFontHeightInPoints((short) 10); - style.setFont(dataFont); - styles.put("data", style); - - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(CellStyle.ALIGN_LEFT); - styles.put("data1", style); - - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(CellStyle.ALIGN_CENTER); - styles.put("data2", style); - - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(CellStyle.ALIGN_RIGHT); - styles.put("data3", style); - - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); -// style.setWrapText(true); - style.setAlignment(CellStyle.ALIGN_CENTER); - style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setFillPattern(CellStyle.SOLID_FOREGROUND); - Font headerFont = wb.createFont(); - headerFont.setFontName("Arial"); - headerFont.setFontHeightInPoints((short) 10); - headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD); - headerFont.setColor(IndexedColors.WHITE.getIndex()); - style.setFont(headerFont); - styles.put("header", style); - - return styles; - } - - /** - * 添加一行 - * @return 行对象 - */ - public Row addRow(){ - return sheet.createRow(rownum++); - } - - /** - * 添加一个单元格 - * @param row 添加的行 - * @param column 添加列号 - * @param val 添加值 - * @return 单元格对象 - */ - public Cell addCell(Row row, int column, Object val){ - return this.addCell(row, column, val, Align.AUTO, Class.class, null); - } - - /** - * 添加一个单元格 - * @param row 添加的行 - * @param column 添加列号 - * @param val 添加值 - * @param align 对齐方式(1:靠左;2:居中;3:靠右) - * @param dataFormat 数值格式(例如:0.00,yyyy-MM-dd) - * @return 单元格对象 - */ - public Cell addCell(Row row, int column, Object val, Align align, Class fieldType, String dataFormat){ - Cell cell = row.createCell(column); - String defaultDataFormat = "@"; - try { - if(val == null){ - cell.setCellValue(""); - }else if(fieldType != Class.class){ - cell.setCellValue((String)fieldType.getMethod("setValue", Object.class).invoke(null, val)); - try{ - defaultDataFormat = (String)fieldType.getMethod("getDataFormat").invoke(null); - } catch (Exception ex) { - defaultDataFormat = "@"; - } - }else{ - if(val instanceof String) { - cell.setCellValue((String) val); - }else if(val instanceof Integer) { - cell.setCellValue((Integer) val); - defaultDataFormat = "0"; - }else if(val instanceof Long) { - cell.setCellValue((Long) val); - defaultDataFormat = "0"; - }else if(val instanceof Double) { - cell.setCellValue((Double) val); - defaultDataFormat = "0.00"; - }else if(val instanceof Float) { - cell.setCellValue((Float) val); - defaultDataFormat = "0.00"; - }else if(val instanceof Date) { - cell.setCellValue((Date) val); - defaultDataFormat = "yyyy-MM-dd HH:mm"; - }else { - cell.setCellValue((String)Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), - "fieldtype."+val.getClass().getSimpleName()+"Type")).getMethod("setValue", Object.class).invoke(null, val)); - } - } -// if (val != null){ - CellStyle style = styles.get("data_column_"+column); - if (style == null){ - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data"+(align.value()>=1&&align.value()<=3?align.value():""))); - if (dataFormat != null){ - defaultDataFormat = dataFormat; - } - style.setDataFormat(wb.createDataFormat().getFormat(defaultDataFormat)); - styles.put("data_column_" + column, style); - } - cell.setCellStyle(style); -// } - } catch (Exception ex) { - log.info("Set cell value ["+row.getRowNum()+","+column+"] error: " + ex.toString()); - cell.setCellValue(val.toString()); - } - return cell; - } - - /** - * 添加数据(通过annotation.ExportField添加数据) - * @return list 数据列表 - */ - public ExcelExport setDataList(List list){ - for (E e : list){ - int colunm = 0; - Row row = this.addRow(); - StringBuilder sb = new StringBuilder(); - for (Object[] os : annotationList){ - ExcelField ef = (ExcelField)os[0]; - Object val = null; - // Get entity value - try{ - if (StringUtils.isNotBlank(ef.attrName())){ - val = ReflectUtils.invokeGetter(e, ef.attrName()); - }else{ - if (os[1] instanceof Field){ - val = ReflectUtils.invokeGetter(e, ((Field)os[1]).getName()); - }else if (os[1] instanceof Method){ - val = ReflectUtils.invokeMethod(e, ((Method)os[1]).getName(), new Class[] {}, new Object[] {}); - } - } - // If is dict, get dict label - if (StringUtils.isNotBlank(ef.dictType())){ - Class dictUtils = Class.forName("com.jeesite.modules.sys.utils.DictUtils"); - val = dictUtils.getMethod("getDictLabel", String.class, String.class, - String.class).invoke(null, val==null?"":val.toString(), ef.dictType(), ""); - //val = DictUtils.getDictLabel(val==null?"":val.toString(), ef.dictType(), ""); - } - }catch(Exception ex) { - // Failure to ignore - log.info(ex.toString()); - val = ""; - } - String dataFormat = ef.dataFormat(); - try { - // 获取Json格式化注解的格式化参数 - JsonFormat jf = e.getClass().getMethod("get"+StringUtils.capitalize(ef.attrName())).getAnnotation(JsonFormat.class); - if (jf != null && jf.pattern() != null){ - dataFormat = jf.pattern(); - } - } catch (Exception e1) { - // 如果获取失败,则使用默认。 - } - this.addCell(row, colunm++, val, ef.align(), ef.fieldType(), dataFormat); - sb.append(val + ", "); - } - log.debug("Write success: ["+row.getRowNum()+"] "+sb.toString()); - } - return this; - } - - /** - * 输出数据流 - * @param os 输出数据流 - */ - public ExcelExport write(OutputStream os){ - try{ - wb.write(os); - }catch(IOException ex){ - log.error(ex.getMessage(), ex); - } - return this; - } - - /** - * 输出到客户端 - * @param fileName 输出文件名 - */ - public ExcelExport write(HttpServletResponse response, String fileName){ - response.reset(); - response.setContentType("application/octet-stream; charset=utf-8"); - response.setHeader("Content-Disposition", "attachment; filename="+EncodeUtils.encodeUrl(fileName)); - try { - write(response.getOutputStream()); - } catch (IOException ex) { - log.error(ex.getMessage(), ex); - } - return this; - } - - /** - * 输出到文件 - * @param fileName 输出文件名 - */ - public ExcelExport writeFile(String name) throws FileNotFoundException, IOException{ - FileOutputStream os = new FileOutputStream(name); - this.write(os); - return this; - } - - /** - * 清理临时文件 - */ - public ExcelExport dispose(){ - if (wb instanceof SXSSFWorkbook){ - ((SXSSFWorkbook)wb).dispose(); - } - return this; - } - -// /** -// * 导出测试 -// */ -// public static void main(String[] args) throws Throwable { -// -// List headerList = ListUtils.newArrayList(); -// for (int i = 1; i <= 10; i++) { -// headerList.add("表头"+i); -// } -// -// List dataRowList = ListUtils.newArrayList(); -// for (int i = 1; i <= headerList.size(); i++) { -// dataRowList.add("数据"+i); -// } -// -// List> dataList = ListUtils.newArrayList(); -// for (int i = 1; i <=100; i++) { -// dataList.add(dataRowList); -// } -// -// ExcelExport ee = new ExcelExport("表格标题", headerList); -// -// for (int i = 0; i < dataList.size(); i++) { -// Row row = ee.addRow(); -// for (int j = 0; j < dataList.get(i).size(); j++) { -// ee.addCell(row, j, dataList.get(i).get(j)); -// } -// } -// -// ee.writeFile("target/export.xlsx"); -// -// ee.dispose(); -// -// log.debug("Export success."); -// -// } - -} +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + */ +package com.jeesite.common.utils.excel; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Comment; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.IndexedColors; +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.ss.util.CellRangeAddress; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.jeesite.common.codec.EncodeUtils; +import com.jeesite.common.collect.ListUtils; +import com.jeesite.common.reflect.ReflectUtils; +import com.jeesite.common.utils.excel.annotation.ExcelField; +import com.jeesite.common.utils.excel.annotation.ExcelField.Align; +import com.jeesite.common.utils.excel.annotation.ExcelFields; +import com.jeesite.common.utils.excel.annotation.ExcelField.Type; + +/** + * 导出Excel文件(导出“XLSX”格式,支持大数据量导出 @see org.apache.poi.ss.SpreadsheetVersion) + * @author ThinkGem + * @version 2013-04-21 + */ +public class ExcelExport { + + private static Logger log = LoggerFactory.getLogger(ExcelExport.class); + + /** + * 工作薄对象 + */ + private Workbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 样式列表 + */ + private Map styles; + + /** + * 当前行号 + */ + private int rownum; + + /** + * 注解列表(Object[]{ ExcelField, Field/Method }) + */ + List annotationList; + + /** + * 构造函数 + * @param title 表格标题,传“空值”,表示无标题 + * @param cls 实体对象,通过annotation.ExportField获取标题 + * @param type 导出类型(1:导出数据) + */ + public ExcelExport(String title, Class cls){ + this(title, cls, Type.EXPORT); + } + + /** + * 构造函数 + * @param title 表格标题,传“空值”,表示无标题 + * @param cls 实体对象,通过annotation.ExportField获取标题 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param groups 导入分组 + */ + public ExcelExport(String title, Class cls, Type type, String... groups){ + this(null, title, cls, type, groups); + } + + /** + * 构造函数 + * @param wb 工作簿对象,支持多个Sheet,通过ExcelExport.createWorkbook()创建 + * @param sheetName,指定Sheet名称 + * @param title 表格标题,传“空值”,表示无标题 + * @param cls 实体对象,通过annotation.ExportField获取标题 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param groups 导入分组 + */ + public ExcelExport(Workbook wb, String title, Class cls, Type type, String... groups){ + if (wb != null){ + this.wb = wb; + }else{ + this.wb = createWorkbook(); + } + this.createSheet(null, title, cls, type, groups); + } + + /** + * 构造函数 + * @param title 表格标题,传“空值”,表示无标题 + * @param headerList 表头数组 + */ + public ExcelExport(String title, List headerList) { + this(null, null, title, headerList); + } + + /** + * 构造函数 + * @param wb 工作簿对象,支持多个Sheet,通过ExcelExport.createWorkbook()创建 + * @param sheetName,指定Sheet名称 + * @param title 表格标题,传“空值”,表示无标题 + * @param headerList 表头列表 + */ + public ExcelExport(Workbook wb, String sheetName, String title, List headerList) { + if (wb != null){ + this.wb = wb; + }else{ + this.wb = createWorkbook(); + } + this.createSheet(sheetName, title, headerList, null); + } + + /** + * 创建一个工作簿 + */ + private Workbook createWorkbook(){ + return new SXSSFWorkbook(500); + } + + /** + * 创建工作表 + * @param sheetName,指定Sheet名称 + * @param title 表格标题,传“空值”,表示无标题 + * @param cls 实体对象,通过annotation.ExportField获取标题 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param groups 导入分组 + */ + public void createSheet(String sheetName, String title, Class cls, Type type, String... groups){ + this.annotationList = ListUtils.newArrayList(); + // Get annotation field + Field[] fs = cls.getDeclaredFields(); + for (Field f : fs){ + ExcelFields efs = f.getAnnotation(ExcelFields.class); + if (efs != null && efs.value() != null){ + for (ExcelField ef : efs.value()){ + addAnnotation(annotationList, ef, f, type, groups); + } + } + ExcelField ef = f.getAnnotation(ExcelField.class); + addAnnotation(annotationList, ef, f, type, groups); + } + // Get annotation method + Method[] ms = cls.getDeclaredMethods(); + for (Method m : ms){ + ExcelFields efs = m.getAnnotation(ExcelFields.class); + if (efs != null && efs.value() != null){ + for (ExcelField ef : efs.value()){ + addAnnotation(annotationList, ef, m, type, groups); + } + } + ExcelField ef = m.getAnnotation(ExcelField.class); + addAnnotation(annotationList, ef, m, type, groups); + } + // Field sorting + Collections.sort(annotationList, new Comparator() { + @Override + public int compare(Object[] o1, Object[] o2) { + return new Integer(((ExcelField)o1[0]).sort()).compareTo( + new Integer(((ExcelField)o2[0]).sort())); + }; + }); + // Initialize + List headerList = ListUtils.newArrayList(); + List headerWidthList = ListUtils.newArrayList(); + for (Object[] os : annotationList){ + ExcelField ef = (ExcelField)os[0]; + String headerTitle = ef.title(); + // 如果是导出,则去掉注释 + if (type == Type.EXPORT){ + String[] ss = StringUtils.split(headerTitle, "**", 2); + if (ss.length == 2){ + headerTitle = ss[0]; + } + } + headerList.add(headerTitle); + headerWidthList.add(ef.width()); + } + // 创建工作表 + this.createSheet(sheetName, title, headerList, headerWidthList); + } + + /** + * 添加到 annotationList + */ + private void addAnnotation(List annotationList, ExcelField ef, Object fOrM, Type type, String... groups){ +// if (ef != null && (ef.type()==0 || ef.type()==type)){ + if (ef != null && (ef.type() == Type.ALL || ef.type() == type)){ + if (groups != null && groups.length > 0){ + boolean inGroup = false; + for (String g : groups){ + if (inGroup){ + break; + } + for (String efg : ef.groups()){ + if (StringUtils.equals(g, efg)){ + inGroup = true; + annotationList.add(new Object[]{ef, fOrM}); + break; + } + } + } + }else{ + annotationList.add(new Object[]{ef, fOrM}); + } + } + } + + /** + * 创建工作表 + * @param sheetName,指定Sheet名称 + * @param title 表格标题,传“空值”,表示无标题 + * @param cls 实体对象,通过annotation.ExportField获取标题 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param groups 导入分组 + */ + public void createSheet(String sheetName, String title, List headerList, List headerWidthList) { + this.sheet = wb.createSheet(StringUtils.defaultString(sheetName, "Export")); + this.styles = createStyles(wb); + // Create title + if (StringUtils.isNotBlank(title)){ + Row titleRow = sheet.createRow(rownum++); + titleRow.setHeightInPoints(30); + Cell titleCell = titleRow.createCell(0); + titleCell.setCellStyle(styles.get("title")); + titleCell.setCellValue(title); + sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), + titleRow.getRowNum(), titleRow.getRowNum(), headerList.size()-1)); + } + // Create header + if (headerList == null){ + throw new ExcelException("headerList not null!"); + } + Row headerRow = sheet.createRow(rownum++); + headerRow.setHeightInPoints(16); + for (int i = 0; i < headerList.size(); i++) { + Cell cell = headerRow.createCell(i); + cell.setCellStyle(styles.get("header")); + String[] ss = StringUtils.split(headerList.get(i), "**", 2); + if (ss.length==2){ + cell.setCellValue(ss[0]); + Comment comment = this.sheet.createDrawingPatriarch().createCellComment( + new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6)); + comment.setString(new XSSFRichTextString(ss[1])); + cell.setCellComment(comment); + }else{ + cell.setCellValue(headerList.get(i)); + } +// sheet.autoSizeColumn(i); + } + boolean isDefWidth = (headerWidthList != null && headerWidthList.size() == headerList.size()); + for (int i = 0; i < headerList.size(); i++) { + int colWidth = -1; + if (isDefWidth){ + colWidth = headerWidthList.get(i); + } + if (colWidth == -1){ + colWidth = sheet.getColumnWidth(i)*2; + colWidth = colWidth < 3000 ? 3000 : colWidth; + } + if (colWidth == 0){ + sheet.setColumnHidden(i, true); + }else{ + sheet.setColumnWidth(i, colWidth); + } + } + log.debug("Create sheet {0} success.", sheetName); + } + +// /** +// * 构造函数 +// * @param title 表格标题,传“空值”,表示无标题 +// * @param headers 表头数组 +// */ +// public ExcelExport(String title, List headerList) { +// this(null, null, title, headerList); +// } +// +// /** +// * 构造函数 +// * @param wb 工作簿对象,支持多个Sheet,通过ExcelExport.createWorkbook()创建 +// * @param sheetName,指定Sheet名称 +// * @param title 表格标题,传“空值”,表示无标题 +// * @param headerList 表头列表 +// */ +// public ExcelExport(Workbook wb, String sheetName, String title, List headerList) { +// initialize(wb, sheetName, title, headerList, null); +// } + + /** + * 创建表格样式 + * @param wb 工作薄对象 + * @return 样式列表 + */ + private Map createStyles(Workbook wb) { + Map styles = new HashMap(); + + CellStyle style = wb.createCellStyle(); + style.setAlignment(CellStyle.ALIGN_CENTER); + style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); + Font titleFont = wb.createFont(); + titleFont.setFontName("Arial"); + titleFont.setFontHeightInPoints((short) 16); + titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD); + style.setFont(titleFont); + styles.put("title", style); + + style = wb.createCellStyle(); + style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); + style.setBorderRight(CellStyle.BORDER_THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(CellStyle.BORDER_THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(CellStyle.BORDER_THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(CellStyle.BORDER_THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + style.setFont(dataFont); + styles.put("data", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(CellStyle.ALIGN_LEFT); + styles.put("data1", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(CellStyle.ALIGN_CENTER); + styles.put("data2", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(CellStyle.ALIGN_RIGHT); + styles.put("data3", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); +// style.setWrapText(true); + style.setAlignment(CellStyle.ALIGN_CENTER); + style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(CellStyle.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeightInPoints((short) 10); + headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD); + headerFont.setColor(IndexedColors.WHITE.getIndex()); + style.setFont(headerFont); + styles.put("header", style); + + return styles; + } + + /** + * 添加一行 + * @return 行对象 + */ + public Row addRow(){ + return sheet.createRow(rownum++); + } + + /** + * 添加一个单元格 + * @param row 添加的行 + * @param column 添加列号 + * @param val 添加值 + * @return 单元格对象 + */ + public Cell addCell(Row row, int column, Object val){ + return this.addCell(row, column, val, Align.AUTO, Class.class, null); + } + + /** + * 添加一个单元格 + * @param row 添加的行 + * @param column 添加列号 + * @param val 添加值 + * @param align 对齐方式(1:靠左;2:居中;3:靠右) + * @param dataFormat 数值格式(例如:0.00,yyyy-MM-dd) + * @return 单元格对象 + */ + public Cell addCell(Row row, int column, Object val, Align align, Class fieldType, String dataFormat){ + Cell cell = row.createCell(column); + String defaultDataFormat = "@"; + try { + if(val == null){ + cell.setCellValue(""); + }else if(fieldType != Class.class){ + cell.setCellValue((String)fieldType.getMethod("setValue", Object.class).invoke(null, val)); + try{ + defaultDataFormat = (String)fieldType.getMethod("getDataFormat").invoke(null); + } catch (Exception ex) { + defaultDataFormat = "@"; + } + }else{ + if(val instanceof String) { + cell.setCellValue((String) val); + }else if(val instanceof Integer) { + cell.setCellValue((Integer) val); + defaultDataFormat = "0"; + }else if(val instanceof Long) { + cell.setCellValue((Long) val); + defaultDataFormat = "0"; + }else if(val instanceof Double) { + cell.setCellValue((Double) val); + defaultDataFormat = "0.00"; + }else if(val instanceof Float) { + cell.setCellValue((Float) val); + defaultDataFormat = "0.00"; + }else if(val instanceof Date) { + cell.setCellValue((Date) val); + defaultDataFormat = "yyyy-MM-dd HH:mm"; + }else { + cell.setCellValue((String)Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), + "fieldtype."+val.getClass().getSimpleName()+"Type")).getMethod("setValue", Object.class).invoke(null, val)); + } + } +// if (val != null){ + CellStyle style = styles.get("data_column_"+column); + if (style == null){ + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data"+(align.value()>=1&&align.value()<=3?align.value():""))); + if (dataFormat != null){ + defaultDataFormat = dataFormat; + } + style.setDataFormat(wb.createDataFormat().getFormat(defaultDataFormat)); + styles.put("data_column_" + column, style); + } + cell.setCellStyle(style); +// } + } catch (Exception ex) { + log.info("Set cell value ["+row.getRowNum()+","+column+"] error: " + ex.toString()); + cell.setCellValue(val.toString()); + } + return cell; + } + + /** + * 添加数据(通过annotation.ExportField添加数据) + * @return list 数据列表 + */ + public ExcelExport setDataList(List list){ + for (E e : list){ + int colunm = 0; + Row row = this.addRow(); + StringBuilder sb = new StringBuilder(); + for (Object[] os : annotationList){ + ExcelField ef = (ExcelField)os[0]; + Object val = null; + // Get entity value + try{ + if (StringUtils.isNotBlank(ef.attrName())){ + val = ReflectUtils.invokeGetter(e, ef.attrName()); + }else{ + if (os[1] instanceof Field){ + val = ReflectUtils.invokeGetter(e, ((Field)os[1]).getName()); + }else if (os[1] instanceof Method){ + val = ReflectUtils.invokeMethod(e, ((Method)os[1]).getName(), new Class[] {}, new Object[] {}); + } + } + // If is dict, get dict label + if (StringUtils.isNotBlank(ef.dictType())){ + Class dictUtils = Class.forName("com.jeesite.modules.sys.utils.DictUtils"); + val = dictUtils.getMethod("getDictLabel", String.class, String.class, + String.class).invoke(null, val==null?"":val.toString(), ef.dictType(), ""); + //val = DictUtils.getDictLabel(val==null?"":val.toString(), ef.dictType(), ""); + } + }catch(Exception ex) { + // Failure to ignore + log.info(ex.toString()); + val = ""; + } + String dataFormat = ef.dataFormat(); + try { + // 获取Json格式化注解的格式化参数 + JsonFormat jf = e.getClass().getMethod("get"+StringUtils.capitalize(ef.attrName())).getAnnotation(JsonFormat.class); + if (jf != null && jf.pattern() != null){ + dataFormat = jf.pattern(); + } + } catch (Exception e1) { + // 如果获取失败,则使用默认。 + } + this.addCell(row, colunm++, val, ef.align(), ef.fieldType(), dataFormat); + sb.append(val + ", "); + } + log.debug("Write success: ["+row.getRowNum()+"] "+sb.toString()); + } + return this; + } + + /** + * 输出数据流 + * @param os 输出数据流 + */ + public ExcelExport write(OutputStream os){ + try{ + wb.write(os); + }catch(IOException ex){ + log.error(ex.getMessage(), ex); + } + return this; + } + + /** + * 输出到客户端 + * @param fileName 输出文件名 + */ + public ExcelExport write(HttpServletResponse response, String fileName){ + response.reset(); + response.setContentType("application/octet-stream; charset=utf-8"); + response.setHeader("Content-Disposition", "attachment; filename="+EncodeUtils.encodeUrl(fileName)); + try { + write(response.getOutputStream()); + } catch (IOException ex) { + log.error(ex.getMessage(), ex); + } + return this; + } + + /** + * 输出到文件 + * @param fileName 输出文件名 + */ + public ExcelExport writeFile(String name) throws FileNotFoundException, IOException{ + FileOutputStream os = new FileOutputStream(name); + this.write(os); + return this; + } + + /** + * 清理临时文件 + */ + public ExcelExport dispose(){ + if (wb instanceof SXSSFWorkbook){ + ((SXSSFWorkbook)wb).dispose(); + } + return this; + } + +// /** +// * 导出测试 +// */ +// public static void main(String[] args) throws Throwable { +// +// List headerList = ListUtils.newArrayList(); +// for (int i = 1; i <= 10; i++) { +// headerList.add("表头"+i); +// } +// +// List dataRowList = ListUtils.newArrayList(); +// for (int i = 1; i <= headerList.size(); i++) { +// dataRowList.add("数据"+i); +// } +// +// List> dataList = ListUtils.newArrayList(); +// for (int i = 1; i <=100; i++) { +// dataList.add(dataRowList); +// } +// +// ExcelExport ee = new ExcelExport("表格标题", headerList); +// +// for (int i = 0; i < dataList.size(); i++) { +// Row row = ee.addRow(); +// for (int j = 0; j < dataList.get(i).size(); j++) { +// ee.addCell(row, j, dataList.get(i).get(j)); +// } +// } +// +// ee.writeFile("target/export.xlsx"); +// +// ee.dispose(); +// +// log.debug("Export success."); +// +// } + +} diff --git a/common/src/main/java/com/jeesite/common/utils/excel/ExcelImport.java b/common/src/main/java/com/jeesite/common/utils/excel/ExcelImport.java index ab2e7b4f..3f3ff9ad 100644 --- a/common/src/main/java/com/jeesite/common/utils/excel/ExcelImport.java +++ b/common/src/main/java/com/jeesite/common/utils/excel/ExcelImport.java @@ -1,441 +1,457 @@ -/** - * Copyright (c) 2013-Now http://jeesite.com All rights reserved. - */ -package com.jeesite.common.utils.excel; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.text.DecimalFormat; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.List; - -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.openxml4j.exceptions.InvalidFormatException; -import org.apache.poi.ss.formula.eval.ErrorEval; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellValue; -import org.apache.poi.ss.usermodel.DateUtil; -import org.apache.poi.ss.usermodel.FormulaEvaluator; -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.XSSFWorkbook; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.multipart.MultipartFile; - -import com.jeesite.common.callback.MethodCallback; -import com.jeesite.common.collect.ListUtils; -import com.jeesite.common.lang.DateUtils; -import com.jeesite.common.lang.ObjectUtils; -import com.jeesite.common.lang.StringUtils; -import com.jeesite.common.reflect.ReflectUtils; -import com.jeesite.common.utils.excel.annotation.ExcelField; -import com.jeesite.common.utils.excel.annotation.ExcelField.Type; -import com.jeesite.common.utils.excel.annotation.ExcelFields; - -/** - * 导入Excel文件(支持“XLS”和“XLSX”格式) - * @author ThinkGem - * @version 2014-8-19 - */ -public class ExcelImport { - - private static Logger log = LoggerFactory.getLogger(ExcelImport.class); - - /** - * 工作薄对象 - */ - private Workbook wb; - - /** - * 工作表对象 - */ - private Sheet sheet; - - /** - * 标题行数 - */ - private int headerNum; - - /** - * 构造函数 - * @param path 导入文件对象,读取第一个工作表 - * @throws InvalidFormatException - * @throws IOException - */ - public ExcelImport(File file) throws InvalidFormatException, IOException { - this(file, 0, 0); - } - - /** - * 构造函数 - * @param path 导入文件对象,读取第一个工作表 - * @param headerNum 标题行数,数据行号=标题行数+1 - * @throws InvalidFormatException - * @throws IOException - */ - public ExcelImport(File file, int headerNum) - throws InvalidFormatException, IOException { - this(file, headerNum, 0); - } - - /** - * 构造函数 - * @param path 导入文件对象 - * @param headerNum 标题行数,数据行号=标题行数+1 - * @param sheetIndexOrName 工作表编号或名称,从0开始 - * @throws InvalidFormatException - * @throws IOException - */ - public ExcelImport(File file, int headerNum, Object sheetIndexOrName) - throws InvalidFormatException, IOException { - this(file.getName(), new FileInputStream(file), headerNum, sheetIndexOrName); - } - - /** - * 构造函数 - * @param file 导入文件对象 - * @param headerNum 标题行数,数据行号=标题行数+1 - * @param sheetIndexOrName 工作表编号或名称,从0开始 - * @throws InvalidFormatException - * @throws IOException - */ - public ExcelImport(MultipartFile multipartFile, int headerNum, Object sheetIndexOrName) - throws InvalidFormatException, IOException { - this(multipartFile.getOriginalFilename(), multipartFile.getInputStream(), headerNum, sheetIndexOrName); - } - - /** - * 构造函数 - * @param path 导入文件对象 - * @param headerNum 标题行数,数据行号=标题行数+1 - * @param sheetIndexOrName 工作表编号或名称 - * @throws InvalidFormatException - * @throws IOException - */ - public ExcelImport(String fileName, InputStream is, int headerNum, Object sheetIndexOrName) - throws InvalidFormatException, IOException { - if (StringUtils.isBlank(fileName)){ - throw new ExcelException("导入文档为空!"); - }else if(fileName.toLowerCase().endsWith("xls")){ - this.wb = new HSSFWorkbook(is); - }else if(fileName.toLowerCase().endsWith("xlsx")){ - this.wb = new XSSFWorkbook(is); - }else{ - throw new ExcelException("文档格式不正确!"); - } - if (sheetIndexOrName instanceof Integer || sheetIndexOrName instanceof Long){ - this.sheet = this.wb.getSheetAt(ObjectUtils.toInteger(sheetIndexOrName)); - }else{ - this.sheet = this.wb.getSheet(ObjectUtils.toString(sheetIndexOrName)); - } - if (this.sheet == null){ - throw new ExcelException("没有找到工作表!"); - } - this.headerNum = headerNum; - log.debug("Initialize success."); - } - - /** - * 添加到 annotationList - */ - private void addAnnotation(List annotationList, ExcelField ef, Object fOrM, Type type, String... groups){ -// if (ef != null && (ef.type()==0 || ef.type()==type)){ - if (ef != null && (ef.type() == Type.ALL || ef.type() == type)){ - if (groups!=null && groups.length>0){ - boolean inGroup = false; - for (String g : groups){ - if (inGroup){ - break; - } - for (String efg : ef.groups()){ - if (StringUtils.equals(g, efg)){ - inGroup = true; - annotationList.add(new Object[]{ef, fOrM}); - break; - } - } - } - }else{ - annotationList.add(new Object[]{ef, fOrM}); - } - } - } - - /** - * 获取行对象 - * @param rownum - * @return - */ - public Row getRow(int rownum){ - return this.sheet.getRow(rownum); - } - - /** - * 获取数据行号 - * @return - */ - public int getDataRowNum(){ - return headerNum; - } - - /** - * 获取最后一个数据行号 - * @return - */ - public int getLastDataRowNum(){ - //return this.sheet.getLastRowNum()+headerNum; - return this.sheet.getLastRowNum() + 1; - } - - /** - * 获取最后一个列号 - * @return - */ - public int getLastCellNum(){ - Row row = this.getRow(headerNum); - return row == null ? 0 : row.getLastCellNum(); - } - - /** - * 获取单元格值 - * @param row 获取的行 - * @param column 获取单元格列号 - * @return 单元格值 - */ - public Object getCellValue(Row row, int column){ - Object val = ""; - try{ - Cell cell = row.getCell(column); - if (cell != null){ - if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC){ - val = new DecimalFormat("0").format(cell.getNumericCellValue()); - }else if (cell.getCellType() == Cell.CELL_TYPE_STRING){ - val = cell.getStringCellValue(); - }else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA){ - try { - val = cell.getStringCellValue(); - } catch (Exception e) { - FormulaEvaluator evaluator = cell.getSheet().getWorkbook() - .getCreationHelper().createFormulaEvaluator(); - evaluator.evaluateFormulaCell(cell); - CellValue cellValue = evaluator.evaluate(cell); - switch (cellValue.getCellType()) { - case Cell.CELL_TYPE_NUMERIC: - val = cellValue.getNumberValue(); - break; - case Cell.CELL_TYPE_STRING: - val = cellValue.getStringValue(); - break; - case Cell.CELL_TYPE_BOOLEAN: - val = cellValue.getBooleanValue(); - break; - case Cell.CELL_TYPE_ERROR: - val = ErrorEval.getText(cellValue.getErrorValue()); - break; - default: - val = cell.getCellFormula(); - } - } - }else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN){ - val = cell.getBooleanCellValue(); - }else if (cell.getCellType() == Cell.CELL_TYPE_ERROR){ - val = cell.getErrorCellValue(); - } - } - }catch (Exception e) { - return val; - } - return val; - } - - /** - * 获取导入数据列表 - * @param cls 导入对象类型 - * @param groups 导入分组 - */ - public List getDataList(Class cls, String... groups) throws InstantiationException, IllegalAccessException{ - return getDataList(cls, false, groups); - } - - /** - * 获取导入数据列表 - * @param cls 导入对象类型 - * @param isThrowException 遇见错误是否抛出异常 - * @param groups 导入分组 - */ - public List getDataList(Class cls, final boolean isThrowException, String... groups) throws InstantiationException, IllegalAccessException{ - return getDataList(cls, new MethodCallback() { - @Override - public Object execute(Object... params) { - if (isThrowException){ - Exception ex = (Exception)params[0]; - int rowNum = (int)params[1]; - int columnNum = (int)params[2]; - throw new ExcelException("Get cell value ["+rowNum+","+columnNum+"]", ex); - } - return null; - } - }, groups); - } - /** - * 获取导入数据列表 - * @param cls 导入对象类型 - * @param isThrowException 遇见错误是否抛出异常 - * @param groups 导入分组 - */ - public List getDataList(Class cls, MethodCallback exceptionCallback, String... groups) throws InstantiationException, IllegalAccessException{ - List annotationList = ListUtils.newArrayList(); - // Get annotation field - Field[] fs = cls.getDeclaredFields(); - for (Field f : fs){ - ExcelFields efs = f.getAnnotation(ExcelFields.class); - if (efs != null && efs.value() != null){ - for (ExcelField ef : efs.value()){ - addAnnotation(annotationList, ef, f, Type.IMPORT, groups); - } - } - ExcelField ef = f.getAnnotation(ExcelField.class); - addAnnotation(annotationList, ef, f, Type.IMPORT, groups); - } - // Get annotation method - Method[] ms = cls.getDeclaredMethods(); - for (Method m : ms){ - ExcelFields efs = m.getAnnotation(ExcelFields.class); - if (efs != null && efs.value() != null){ - for (ExcelField ef : efs.value()){ - addAnnotation(annotationList, ef, m, Type.IMPORT, groups); - } - } - ExcelField ef = m.getAnnotation(ExcelField.class); - addAnnotation(annotationList, ef, m, Type.IMPORT, groups); - } - // Field sorting - Collections.sort(annotationList, new Comparator() { - @Override - public int compare(Object[] o1, Object[] o2) { - return new Integer(((ExcelField)o1[0]).sort()).compareTo( - new Integer(((ExcelField)o2[0]).sort())); - }; - }); - //log.debug("Import column count:"+annotationList.size()); - // Get excel data - List dataList = ListUtils.newArrayList(); - for (int i = this.getDataRowNum(); i < this.getLastDataRowNum(); i++) { - E e = (E)cls.newInstance(); - Row row = this.getRow(i); - StringBuilder sb = new StringBuilder(); - for (int j = 0; j < annotationList.size(); j++){//Object[] os : annotationList){ - Object[] os = annotationList.get(j); - ExcelField ef = (ExcelField)os[0]; - int column = (ef.column() != -1) ? ef.column() : j; - Object val = this.getCellValue(row, column); - if (val != null){ - // If is dict type, get dict value - if (StringUtils.isNotBlank(ef.dictType())){ - try{ - Class dictUtils = Class.forName("com.jeesite.modules.sys.utils.DictUtils"); - val = dictUtils.getMethod("getDictValue", String.class, String.class, - String.class).invoke(null, val.toString(), ef.dictType(), ""); - } catch (Exception ex) { - log.info("Get cell value ["+i+","+column+"] error: " + ex.toString()); - val = null; - } - //val = DictUtils.getDictValue(val.toString(), ef.dictType(), ""); - //log.debug("Dictionary type value: ["+i+","+colunm+"] " + val); - } - // Get param type and type cast - Class valType = Class.class; - if (os[1] instanceof Field){ - valType = ((Field)os[1]).getType(); - }else if (os[1] instanceof Method){ - Method method = ((Method)os[1]); - if ("get".equals(method.getName().substring(0, 3))){ - valType = method.getReturnType(); - }else if("set".equals(method.getName().substring(0, 3))){ - valType = ((Method)os[1]).getParameterTypes()[0]; - } - } - //log.debug("Import value type: ["+i+","+column+"] " + valType); - try { - if (valType == String.class){ - String s = String.valueOf(val.toString()); - if(StringUtils.endsWith(s, ".0")){ - val = StringUtils.substringBefore(s, ".0"); - }else{ - val = String.valueOf(val.toString()); - } - }else if (valType == Integer.class){ - val = Double.valueOf(val.toString()).intValue(); - }else if (valType == Long.class){ - val = Double.valueOf(val.toString()).longValue(); - }else if (valType == Double.class){ - val = Double.valueOf(val.toString()); - }else if (valType == Float.class){ - val = Float.valueOf(val.toString()); - }else if (valType == Date.class){ - if (val instanceof String){ - val = DateUtils.parseDate(val); - }else{ - // POI Excel 日期格式转换 - val = DateUtil.getJavaDate((Double)val); - } - }else{ - if (ef.fieldType() != Class.class){ - val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val.toString()); - }else{ - val = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), - "fieldtype."+valType.getSimpleName()+"Type")).getMethod("getValue", String.class).invoke(null, val.toString()); - } - } - } catch (Exception ex) { - log.info("Get cell value ["+i+","+column+"] error: " + ex.toString()); - val = null; - // 参数:Exception ex, int rowNum, int columnNum - exceptionCallback.execute(ex, i, column); - } - // set entity value - if (os[1] instanceof Field){ - ReflectUtils.invokeSetter(e, ((Field)os[1]).getName(), val); - }else if (os[1] instanceof Method){ - String mthodName = ((Method)os[1]).getName(); - if ("get".equals(mthodName.substring(0, 3))){ - mthodName = "set"+StringUtils.substringAfter(mthodName, "get"); - } - ReflectUtils.invokeMethod(e, mthodName, new Class[] {valType}, new Object[] {val}); - } - } - sb.append(val+", "); - } - dataList.add(e); - log.debug("Read success: ["+i+"] "+sb.toString()); - } - return dataList; - } - -// /** -// * 导入测试 -// */ -// public static void main(String[] args) throws Throwable { -// -// ImportExcel ei = new ImportExcel("target/export.xlsx", 1); -// -// for (int i = ei.getDataRowNum(); i < ei.getLastDataRowNum(); i++) { -// Row row = ei.getRow(i); -// for (int j = 0; j < ei.getLastCellNum(); j++) { -// Object val = ei.getCellValue(row, j); -// System.out.print(val+", "); -// } -// System.out.print("\n"); -// } -// -// } - -} +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + */ +package com.jeesite.common.utils.excel; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.text.DecimalFormat; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; + +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellValue; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.FormulaEvaluator; +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.XSSFWorkbook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.multipart.MultipartFile; + +import com.jeesite.common.callback.MethodCallback; +import com.jeesite.common.collect.ListUtils; +import com.jeesite.common.lang.DateUtils; +import com.jeesite.common.lang.ObjectUtils; +import com.jeesite.common.lang.StringUtils; +import com.jeesite.common.reflect.ReflectUtils; +import com.jeesite.common.utils.excel.annotation.ExcelField; +import com.jeesite.common.utils.excel.annotation.ExcelField.Type; +import com.jeesite.common.utils.excel.annotation.ExcelFields; + +/** + * 导入Excel文件(支持“XLS”和“XLSX”格式) + * @author ThinkGem + * @version 2014-8-19 + */ +public class ExcelImport { + + private static Logger log = LoggerFactory.getLogger(ExcelImport.class); + + /** + * 工作薄对象 + */ + private Workbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 标题行数 + */ + private int headerNum; + + /** + * 构造函数 + * @param path 导入文件对象,读取第一个工作表 + * @throws InvalidFormatException + * @throws IOException + */ + public ExcelImport(File file) throws InvalidFormatException, IOException { + this(file, 0, 0); + } + + /** + * 构造函数 + * @param path 导入文件对象,读取第一个工作表 + * @param headerNum 标题行数,数据行号=标题行数+1 + * @throws InvalidFormatException + * @throws IOException + */ + public ExcelImport(File file, int headerNum) + throws InvalidFormatException, IOException { + this(file, headerNum, 0); + } + + /** + * 构造函数 + * @param path 导入文件对象 + * @param headerNum 标题行数,数据行号=标题行数+1 + * @param sheetIndexOrName 工作表编号或名称,从0开始 + * @throws InvalidFormatException + * @throws IOException + */ + public ExcelImport(File file, int headerNum, Object sheetIndexOrName) + throws InvalidFormatException, IOException { + this(file.getName(), new FileInputStream(file), headerNum, sheetIndexOrName); + } + + /** + * 构造函数 + * @param file 导入文件对象 + * @param headerNum 标题行数,数据行号=标题行数+1 + * @param sheetIndexOrName 工作表编号或名称,从0开始 + * @throws InvalidFormatException + * @throws IOException + */ + public ExcelImport(MultipartFile multipartFile, int headerNum, Object sheetIndexOrName) + throws InvalidFormatException, IOException { + this(multipartFile.getOriginalFilename(), multipartFile.getInputStream(), headerNum, sheetIndexOrName); + } + + /** + * 构造函数 + * @param path 导入文件对象 + * @param headerNum 标题行数,数据行号=标题行数+1 + * @param sheetIndexOrName 工作表编号或名称 + * @throws InvalidFormatException + * @throws IOException + */ + public ExcelImport(String fileName, InputStream is, int headerNum, Object sheetIndexOrName) + throws InvalidFormatException, IOException { + if (StringUtils.isBlank(fileName)){ + throw new ExcelException("导入文档为空!"); + }else if(fileName.toLowerCase().endsWith("xls")){ + this.wb = new HSSFWorkbook(is); + }else if(fileName.toLowerCase().endsWith("xlsx")){ + this.wb = new XSSFWorkbook(is); + }else{ + throw new ExcelException("文档格式不正确!"); + } + this.setSheet(sheetIndexOrName, headerNum); + log.debug("Initialize success."); + } + + /** + * 添加到 annotationList + */ + private void addAnnotation(List annotationList, ExcelField ef, Object fOrM, Type type, String... groups){ +// if (ef != null && (ef.type()==0 || ef.type()==type)){ + if (ef != null && (ef.type() == Type.ALL || ef.type() == type)){ + if (groups!=null && groups.length>0){ + boolean inGroup = false; + for (String g : groups){ + if (inGroup){ + break; + } + for (String efg : ef.groups()){ + if (StringUtils.equals(g, efg)){ + inGroup = true; + annotationList.add(new Object[]{ef, fOrM}); + break; + } + } + } + }else{ + annotationList.add(new Object[]{ef, fOrM}); + } + } + } + + /** + * 获取当前工作薄 + * @author ThinkGem + */ + public Workbook getWorkbook() { + return wb; + } + + /** + * 设置当前工作表和标题行数 + * @author ThinkGem + */ + public void setSheet(Object sheetIndexOrName, int headerNum) { + if (sheetIndexOrName instanceof Integer || sheetIndexOrName instanceof Long){ + this.sheet = this.wb.getSheetAt(ObjectUtils.toInteger(sheetIndexOrName)); + }else{ + this.sheet = this.wb.getSheet(ObjectUtils.toString(sheetIndexOrName)); + } + if (this.sheet == null){ + throw new ExcelException("没有找到‘"+sheetIndexOrName+"’工作表!"); + } + this.headerNum = headerNum; + } + + /** + * 获取行对象 + * @param rownum + * @return + */ + public Row getRow(int rownum){ + return this.sheet.getRow(rownum); + } + + /** + * 获取数据行号 + * @return + */ + public int getDataRowNum(){ + return headerNum; + } + + /** + * 获取最后一个数据行号 + * @return + */ + public int getLastDataRowNum(){ + //return this.sheet.getLastRowNum() + headerNum; + return this.sheet.getLastRowNum() + 1; + } + + /** + * 获取最后一个列号 + * @return + */ + public int getLastCellNum(){ + Row row = this.getRow(headerNum); + return row == null ? 0 : row.getLastCellNum(); + } + + /** + * 获取单元格值 + * @param row 获取的行 + * @param column 获取单元格列号 + * @return 单元格值 + */ + public Object getCellValue(Row row, int column){ + Object val = ""; + try{ + Cell cell = row.getCell(column); + if (cell != null){ + if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC){ + val = new DecimalFormat("0").format(cell.getNumericCellValue()); + }else if (cell.getCellType() == Cell.CELL_TYPE_STRING){ + val = cell.getStringCellValue(); + }else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA){ + try { + val = cell.getStringCellValue(); + } catch (Exception e) { + FormulaEvaluator evaluator = cell.getSheet().getWorkbook() + .getCreationHelper().createFormulaEvaluator(); + evaluator.evaluateFormulaCell(cell); + CellValue cellValue = evaluator.evaluate(cell); + switch (cellValue.getCellType()) { + case Cell.CELL_TYPE_NUMERIC: + val = cellValue.getNumberValue(); + break; + case Cell.CELL_TYPE_STRING: + val = cellValue.getStringValue(); + break; + case Cell.CELL_TYPE_BOOLEAN: + val = cellValue.getBooleanValue(); + break; + case Cell.CELL_TYPE_ERROR: + val = ErrorEval.getText(cellValue.getErrorValue()); + break; + default: + val = cell.getCellFormula(); + } + } + }else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN){ + val = cell.getBooleanCellValue(); + }else if (cell.getCellType() == Cell.CELL_TYPE_ERROR){ + val = cell.getErrorCellValue(); + } + } + }catch (Exception e) { + return val; + } + return val; + } + + /** + * 获取导入数据列表 + * @param cls 导入对象类型 + * @param groups 导入分组 + */ + public List getDataList(Class cls, String... groups) throws InstantiationException, IllegalAccessException{ + return getDataList(cls, false, groups); + } + + /** + * 获取导入数据列表 + * @param cls 导入对象类型 + * @param isThrowException 遇见错误是否抛出异常 + * @param groups 导入分组 + */ + public List getDataList(Class cls, final boolean isThrowException, String... groups) throws InstantiationException, IllegalAccessException{ + return getDataList(cls, new MethodCallback() { + @Override + public Object execute(Object... params) { + if (isThrowException){ + Exception ex = (Exception)params[0]; + int rowNum = (int)params[1]; + int columnNum = (int)params[2]; + throw new ExcelException("Get cell value ["+rowNum+","+columnNum+"]", ex); + } + return null; + } + }, groups); + } + /** + * 获取导入数据列表 + * @param cls 导入对象类型 + * @param isThrowException 遇见错误是否抛出异常 + * @param groups 导入分组 + */ + public List getDataList(Class cls, MethodCallback exceptionCallback, String... groups) throws InstantiationException, IllegalAccessException{ + List annotationList = ListUtils.newArrayList(); + // Get annotation field + Field[] fs = cls.getDeclaredFields(); + for (Field f : fs){ + ExcelFields efs = f.getAnnotation(ExcelFields.class); + if (efs != null && efs.value() != null){ + for (ExcelField ef : efs.value()){ + addAnnotation(annotationList, ef, f, Type.IMPORT, groups); + } + } + ExcelField ef = f.getAnnotation(ExcelField.class); + addAnnotation(annotationList, ef, f, Type.IMPORT, groups); + } + // Get annotation method + Method[] ms = cls.getDeclaredMethods(); + for (Method m : ms){ + ExcelFields efs = m.getAnnotation(ExcelFields.class); + if (efs != null && efs.value() != null){ + for (ExcelField ef : efs.value()){ + addAnnotation(annotationList, ef, m, Type.IMPORT, groups); + } + } + ExcelField ef = m.getAnnotation(ExcelField.class); + addAnnotation(annotationList, ef, m, Type.IMPORT, groups); + } + // Field sorting + Collections.sort(annotationList, new Comparator() { + @Override + public int compare(Object[] o1, Object[] o2) { + return new Integer(((ExcelField)o1[0]).sort()).compareTo( + new Integer(((ExcelField)o2[0]).sort())); + }; + }); + //log.debug("Import column count:"+annotationList.size()); + // Get excel data + List dataList = ListUtils.newArrayList(); + for (int i = this.getDataRowNum(); i < this.getLastDataRowNum(); i++) { + E e = (E)cls.newInstance(); + Row row = this.getRow(i); + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < annotationList.size(); j++){//Object[] os : annotationList){ + Object[] os = annotationList.get(j); + ExcelField ef = (ExcelField)os[0]; + int column = (ef.column() != -1) ? ef.column() : j; + Object val = this.getCellValue(row, column); + if (val != null){ + // If is dict type, get dict value + if (StringUtils.isNotBlank(ef.dictType())){ + try{ + Class dictUtils = Class.forName("com.jeesite.modules.sys.utils.DictUtils"); + val = dictUtils.getMethod("getDictValue", String.class, String.class, + String.class).invoke(null, val.toString(), ef.dictType(), ""); + } catch (Exception ex) { + log.info("Get cell value ["+i+","+column+"] error: " + ex.toString()); + val = null; + } + //val = DictUtils.getDictValue(val.toString(), ef.dictType(), ""); + //log.debug("Dictionary type value: ["+i+","+colunm+"] " + val); + } + // Get param type and type cast + Class valType = Class.class; + if (os[1] instanceof Field){ + valType = ((Field)os[1]).getType(); + }else if (os[1] instanceof Method){ + Method method = ((Method)os[1]); + if ("get".equals(method.getName().substring(0, 3))){ + valType = method.getReturnType(); + }else if("set".equals(method.getName().substring(0, 3))){ + valType = ((Method)os[1]).getParameterTypes()[0]; + } + } + //log.debug("Import value type: ["+i+","+column+"] " + valType); + try { + if (valType == String.class){ + String s = String.valueOf(val.toString()); + if(StringUtils.endsWith(s, ".0")){ + val = StringUtils.substringBefore(s, ".0"); + }else{ + val = String.valueOf(val.toString()); + } + }else if (valType == Integer.class){ + val = Double.valueOf(val.toString()).intValue(); + }else if (valType == Long.class){ + val = Double.valueOf(val.toString()).longValue(); + }else if (valType == Double.class){ + val = Double.valueOf(val.toString()); + }else if (valType == Float.class){ + val = Float.valueOf(val.toString()); + }else if (valType == Date.class){ + if (val instanceof String){ + val = DateUtils.parseDate(val); + }else{ + // POI Excel 日期格式转换 + val = DateUtil.getJavaDate((Double)val); + } + }else{ + if (ef.fieldType() != Class.class){ + val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val.toString()); + }else{ + val = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), + "fieldtype."+valType.getSimpleName()+"Type")).getMethod("getValue", String.class).invoke(null, val.toString()); + } + } + } catch (Exception ex) { + log.info("Get cell value ["+i+","+column+"] error: " + ex.toString()); + val = null; + // 参数:Exception ex, int rowNum, int columnNum + exceptionCallback.execute(ex, i, column); + } + // set entity value + if (os[1] instanceof Field){ + ReflectUtils.invokeSetter(e, ((Field)os[1]).getName(), val); + }else if (os[1] instanceof Method){ + String mthodName = ((Method)os[1]).getName(); + if ("get".equals(mthodName.substring(0, 3))){ + mthodName = "set"+StringUtils.substringAfter(mthodName, "get"); + } + ReflectUtils.invokeMethod(e, mthodName, new Class[] {valType}, new Object[] {val}); + } + } + sb.append(val+", "); + } + dataList.add(e); + log.debug("Read success: ["+i+"] "+sb.toString()); + } + return dataList; + } + +// /** +// * 导入测试 +// */ +// public static void main(String[] args) throws Throwable { +// +// ImportExcel ei = new ImportExcel("target/export.xlsx", 1); +// +// for (int i = ei.getDataRowNum(); i < ei.getLastDataRowNum(); i++) { +// Row row = ei.getRow(i); +// for (int j = 0; j < ei.getLastCellNum(); j++) { +// Object val = ei.getCellValue(row, j); +// System.out.print(val+", "); +// } +// System.out.print("\n"); +// } +// +// } + +} diff --git a/modules/core/src/main/java/com/jeesite/modules/db/InitCoreData.xlsx b/modules/core/src/main/java/com/jeesite/modules/db/InitCoreData.xlsx index 89932279..a2cc279e 100644 Binary files a/modules/core/src/main/java/com/jeesite/modules/db/InitCoreData.xlsx and b/modules/core/src/main/java/com/jeesite/modules/db/InitCoreData.xlsx differ diff --git a/modules/core/src/main/resources/views/modules/sys/sysIndex/topMenu.html b/modules/core/src/main/resources/views/modules/sys/sysIndex/topMenu.html index e6cb3f55..ec13a9fb 100644 --- a/modules/core/src/main/resources/views/modules/sys/sysIndex/topMenu.html +++ b/modules/core/src/main/resources/views/modules/sys/sysIndex/topMenu.html @@ -1,27 +1,26 @@ -<% var productName = @Global.getConfig('productName'); %> -