├── src ├── main │ └── java │ │ └── org │ │ └── javaexcel │ │ ├── model │ │ ├── ExcelType.java │ │ ├── CellType.java │ │ ├── ExcelHeader.java │ │ ├── ExcelFooter.java │ │ ├── ExcelCellStyle.java │ │ ├── CellMerge.java │ │ ├── ExcelTitle.java │ │ ├── ExcelMetaData.java │ │ └── ExcelColor.java │ │ ├── util │ │ ├── Const.java │ │ ├── JsonUtil.java │ │ ├── UUIDUtil.java │ │ └── FileUtils.java │ │ ├── ExcelWriterFactory.java │ │ ├── ExcelWriter.java │ │ ├── xlsx │ │ ├── SpreadSheetWriter.java │ │ └── XmlToExcelWriter.java │ │ └── xls │ │ └── DataToExcelWriter.java └── test │ └── java │ └── org │ └── javaexcel │ └── xlsx │ ├── SimpleReportExportTest.java │ ├── XmlToExcelWriterTest.java │ └── ComplexExcelExportTest.java ├── README.md ├── assembly.xml ├── .gitignore └── pom.xml /src/main/java/org/javaexcel/model/ExcelType.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.model; 2 | 3 | /* 4 | * File name : ExcelType.java 5 | * @Copyright : www.quancheng-ec.com 6 | * Description : javaexcel 7 | * Author : Robert 8 | * CreateTime : 2016年4月7日 9 | */ 10 | public enum ExcelType { 11 | XLS, XLSX 12 | } -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/model/CellType.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.model; 2 | 3 | /* 4 | * File name : CellType.java 5 | * @Copyright : luoyoub@163.com 6 | * Description : javaexcel 7 | * Author : Robert 8 | * CreateTime : 2016年4月1日 9 | */ 10 | public enum CellType { 11 | NUMBER, 12 | INT, 13 | DATE, 14 | MONEY, 15 | TEXT, 16 | PERCENT, 17 | LIST; 18 | } -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/util/Const.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.util; 2 | 3 | /* 4 | * File name : Const.java 5 | * @Copyright : luoyoub@163.com 6 | * Description : javaexcel 7 | * Author : Robert 8 | * CreateTime : 2016年4月2日 9 | */ 10 | public class Const { 11 | public static final String EXCEL_SUFFIX_XLS = ".xls"; 12 | public static final String EXCEL_SUFFIX_XLSX = ".xlsx"; 13 | public static final String XML_SUFFIX = ".xml"; 14 | 15 | public static Integer XLS_ROW_LIMIT = 65536; 16 | public static Integer XLSX_ROW_LIMIT = 1048576; 17 | } -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/ExcelWriterFactory.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel; 2 | 3 | import org.javaexcel.model.ExcelType; 4 | import org.javaexcel.xls.DataToExcelWriter; 5 | import org.javaexcel.xlsx.XmlToExcelWriter; 6 | 7 | /* 8 | * File name : ExcelWriterFactory.java 9 | * @Copyright : www.quancheng-ec.com 10 | * Description : javaexcel 11 | * Author : Robert 12 | * CreateTime : 2016年4月7日 13 | */ 14 | public class ExcelWriterFactory { 15 | public static ExcelWriter getWriter(ExcelType type) { 16 | switch (type) { 17 | case XLS: 18 | return new DataToExcelWriter(); 19 | case XLSX: 20 | return new XmlToExcelWriter(); 21 | default: 22 | return null; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 基于Apache POI的JAVA Excel读写工具包 2 | ======================== 3 | ## Introduction 4 | 5 | java-excel是基于Apache POI的JAVA Excel读写工具。 6 | 写这个工具也是缘由一个项目的Excel读写需求,当我找遍了所有资料,发现没有一个通用的且比较高效的工具可以直接拿来使用,所以在这个项目结束后,对项目中所遇到的问题进行了总结,整理优化了相关代码,供大家学习交流,希望大家多提建议,如果对大家有帮助,我会努力维护好这个工具~ 7 | 8 | 9 | ## Features 10 | 11 | * 基于Apache POI,主要用于提供JAVA Excel读写功能; 12 | * 支持xls和xlsx,xlsx是通过XML方式进行读写,效率有大幅提升,有效防止写Excel时内存溢出; 13 | * 对POI进行了封装,支持自定义表头、标题、列及尾部的字体、颜色、对齐方式; 14 | * 支持二级标题,支持数据行的纵向合并; 15 | * 支持XLSX格式的大数据写入(数据量较大时建议使用xlsx格式进行写入); 16 | * 支持设置单元格边框(包括对合并单元格的边框设置); 17 | 18 | 当前仅支持这么多功能,如果对大家有用,后面将逐步完善其它功能,如果对你毫无帮助,请勿喷~ 19 | 20 | ## Invoke 21 | 22 | ExcelWriter writer = ExcelWriterFactory.getWriter(ExcelType.XLSX); 23 | writer.process(metadata, datas, "/Users/Robert/Desktop/QA_test/expense.xlsx"); 24 | 25 | 如果在使用过程中有任何问题,欢迎提建议、吐槽~ 26 | 27 | email: luoyoub@163.com -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/util/JsonUtil.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.util; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | 6 | /* 7 | * File name : JsonUtil.java 8 | * @Copyright : luoyoub@163.com 9 | * Description : javaexcel 10 | * Author : Robert 11 | * CreateTime : 2016年4月2日 12 | */ 13 | public final class JsonUtil { 14 | private static Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create(); 15 | 16 | public static T stringToBean(String json, Class classOfT) { 17 | return gson.fromJson(json, classOfT); 18 | } 19 | 20 | public static String beanToString(Object object) { 21 | return gson.toJson(object); 22 | } 23 | 24 | public static boolean isEmpty(Object obj) { 25 | return null == obj || "".equals(obj) || 0 == obj.toString().length() ? true : false; 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/model/ExcelHeader.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.model; 2 | 3 | /* 4 | * File name : ExcelHeader.java 5 | * @Copyright : luoyoub@163.com 6 | * Description : javaexcel 7 | * Author : Robert 8 | * CreateTime : 2016年4月1日 9 | */ 10 | public class ExcelHeader { 11 | // 表头名称 12 | private String headerName; 13 | 14 | // 样式 15 | private ExcelCellStyle cellStyle; 16 | 17 | private float rowHeight = 50; 18 | 19 | public float getRowHeight() { 20 | return rowHeight; 21 | } 22 | 23 | public void setRowHeight(float rowHeight) { 24 | this.rowHeight = rowHeight; 25 | } 26 | 27 | public String getHeaderName() { 28 | return headerName; 29 | } 30 | 31 | public void setHeaderName(String headerName) { 32 | this.headerName = headerName; 33 | } 34 | 35 | public ExcelCellStyle getCellStyle() { 36 | return cellStyle; 37 | } 38 | 39 | public void setCellStyle(ExcelCellStyle cellStyle) { 40 | this.cellStyle = cellStyle; 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/model/ExcelFooter.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.model; 2 | 3 | /* 4 | * File name : ExcelFooter.java 5 | * @Copyright : luoyoub@163.com 6 | * Description : javaexcel 7 | * Author : Robert 8 | * CreateTime : 2016年4月1日 9 | */ 10 | public class ExcelFooter { 11 | // EXCEL底部备注 12 | private String remarks; 13 | 14 | // 样式 15 | private ExcelCellStyle cellStyle; 16 | 17 | // 设置行高 18 | private float rowHeight = 25; 19 | 20 | public float getRowHeight() { 21 | return rowHeight; 22 | } 23 | 24 | public void setRowHeight(float rowHeight) { 25 | this.rowHeight = rowHeight; 26 | } 27 | 28 | public String getRemarks() { 29 | return remarks; 30 | } 31 | 32 | public void setRemarks(String remarks) { 33 | this.remarks = remarks; 34 | } 35 | 36 | public ExcelCellStyle getCellStyle() { 37 | return cellStyle; 38 | } 39 | 40 | public void setCellStyle(ExcelCellStyle cellStyle) { 41 | this.cellStyle = cellStyle; 42 | } 43 | } -------------------------------------------------------------------------------- /assembly.xml: -------------------------------------------------------------------------------- 1 | 2 | package 3 | 4 | tar.gz 5 | 6 | true 7 | 8 | 9 | true 10 | lib 11 | false 12 | 13 | 14 | 15 | 16 | ${project.basedir} 17 | / 18 | 19 | README* 20 | pom.xml 21 | 22 | 23 | 24 | ${project.build.directory} 25 | / 26 | 27 | *.jar 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/util/UUIDUtil.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.util; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.util.UUID; 5 | 6 | import org.apache.commons.codec.binary.Base64; 7 | 8 | /* 9 | * File name : UUIDUtil.java 10 | * @Copyright : luoyoub@163.com 11 | * Description : javaexcel 12 | * Author : Robert 13 | * CreateTime : 2016年4月2日 14 | */ 15 | public final class UUIDUtil { 16 | /** 17 | * 获取唯一标识的UUID(32位) 18 | * 19 | * @return 20 | */ 21 | public static String getUUID() { 22 | String uid = UUID.randomUUID().toString(); 23 | return uid.substring(0, 8) + uid.substring(9, 13) + uid.substring(14, 18) + uid.substring(19, 23) 24 | + uid.substring(24); 25 | } 26 | 27 | /** 28 | * 获取22位UUID 29 | * 30 | * @return 31 | */ 32 | public static String getShortUUID() { 33 | UUID uuid = UUID.randomUUID(); 34 | return encode(uuid); 35 | } 36 | 37 | private static String encode(UUID uuid) { 38 | ByteBuffer buffer = ByteBuffer.wrap(new byte[16]); 39 | buffer.putLong(uuid.getMostSignificantBits()); 40 | buffer.putLong(uuid.getLeastSignificantBits()); 41 | return Base64.encodeBase64URLSafeString(buffer.array()); 42 | } 43 | 44 | @SuppressWarnings("unused") 45 | private static UUID decode(String base64) { 46 | if (base64.length() != 22) { 47 | throw new IllegalArgumentException("Not a valid Base64 encoded UUID"); 48 | } 49 | ByteBuffer buffer = ByteBuffer.wrap(Base64.decodeBase64(base64)); 50 | if (buffer.capacity() != 16) { 51 | throw new IllegalArgumentException("Not a valid Base64 encoded UUID"); 52 | } 53 | return new UUID(buffer.getLong(), buffer.getLong()); 54 | } 55 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # .gitignore for maven 2 | target/ 3 | *.releaseBackup 4 | 5 | # IDE support files 6 | /.classpath 7 | /.launch 8 | /.project 9 | /.settings 10 | /*.launch 11 | /*.tmproj 12 | /ivy* 13 | /eclipse 14 | 15 | # default HSQL database files for production mode 16 | /prodDb.* 17 | 18 | # general HSQL database files 19 | *Db.properties 20 | *Db.script 21 | 22 | # logs 23 | /stacktrace.log 24 | /test/reports 25 | /logs 26 | *.log 27 | *.log.* 28 | 29 | 30 | # plugin release file 31 | /*.zip 32 | /*.zip.sha1 33 | 34 | # "temporary" build files 35 | target/ 36 | out/ 37 | build/ 38 | 39 | # other 40 | *.iws 41 | 42 | #.gitignore for java 43 | *.class 44 | 45 | #Package Files# 46 | *.jar 47 | 48 | ## .gitignore for eclipse 49 | *.pydevproject 50 | .project 51 | .metadata 52 | tmp/** 53 | tmp/**/* 54 | *.tmp 55 | *.bak 56 | *.swp 57 | *~.nib 58 | local.properties 59 | .classpath 60 | .settings/ 61 | .loadpath 62 | 63 | # External tool builders 64 | .externalToolBuilders/ 65 | 66 | # Locally stored "Eclipse launch configurations" 67 | *.launch 68 | 69 | # CDT-specific 70 | .cproject 71 | 72 | # PDT-specific 73 | .buildpath 74 | 75 | ## .gitignore for intellij 76 | 77 | *.iml 78 | *.ipr 79 | *.iws 80 | .idea/ 81 | 82 | ## .gitignore for linux 83 | .* 84 | !.gitignore 85 | *~ 86 | 87 | ## .gitignore for windows 88 | 89 | # Windows image file caches 90 | Thumbs.db 91 | ehthumbs.db 92 | 93 | # Folder config file 94 | Desktop.ini 95 | 96 | # Recycle Bin used on file shares 97 | $RECYCLE.BIN/ 98 | 99 | ## .gitignore for mac os x 100 | .DS_Store 101 | .AppleDouble 102 | .LSOverride 103 | Icon 104 | 105 | 106 | # Thumbnails 107 | ._* 108 | 109 | # Files that might appear on external disk 110 | .Spotlight-V100 111 | .Trashes 112 | 113 | ## hack for graddle wrapper 114 | !wrapper/*.jar 115 | !**/wrapper/*.jar 116 | 117 | -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/model/ExcelCellStyle.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.model; 2 | 3 | import org.apache.poi.ss.usermodel.CellStyle; 4 | 5 | /* 6 | * File name : CellStyle.java 7 | * @Copyright : luoyoub@163.com 8 | * Description : javaexcel 9 | * Author : Robert 10 | * CreateTime : 2016年4月1日 11 | */ 12 | public class ExcelCellStyle { 13 | // 水平居中 14 | private short align = CellStyle.ALIGN_LEFT; 15 | 16 | // 垂直居中 17 | private short verticalAlign = CellStyle.VERTICAL_CENTER; 18 | 19 | // 字体大小 20 | private short size = 11; 21 | 22 | // 字体颜色 23 | private short color = ExcelColor.DEFAULT_COLOR; 24 | 25 | // 单元格背景色 26 | private short backgroundColor = ExcelColor.WHITE; 27 | 28 | // 斜体 29 | private boolean isItalic = false; 30 | 31 | public boolean isItalic() { 32 | return isItalic; 33 | } 34 | 35 | public void setItalic(boolean isItalic) { 36 | this.isItalic = isItalic; 37 | } 38 | 39 | public short getSize() { 40 | return size; 41 | } 42 | 43 | public short getAlign() { 44 | return align; 45 | } 46 | 47 | public void setAlign(short align) { 48 | this.align = align; 49 | } 50 | 51 | public short getVerticalAlign() { 52 | return verticalAlign; 53 | } 54 | 55 | public void setVerticalAlign(short verticalAlign) { 56 | this.verticalAlign = verticalAlign; 57 | } 58 | 59 | public void setSize(short size) { 60 | this.size = size; 61 | } 62 | 63 | public short getColor() { 64 | return color; 65 | } 66 | 67 | public void setColor(short color) { 68 | this.color = color; 69 | } 70 | 71 | public short getBackgroundColor() { 72 | return backgroundColor; 73 | } 74 | 75 | public void setBackgroundColor(short backgroundColor) { 76 | this.backgroundColor = backgroundColor; 77 | } 78 | } -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/model/CellMerge.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.model; 2 | 3 | import org.apache.poi.hssf.util.CellReference; 4 | 5 | /* 6 | * File name : MergeCell.java 7 | * @Copyright : luoyoub@163.com 8 | * Description : excelservice-service 9 | * Author : Robert 10 | * CreateTime : 2016年4月1日 11 | */ 12 | public class CellMerge { 13 | private int beginColumn; 14 | private int endColumn; 15 | private int beginCell; 16 | private int endCell; 17 | 18 | public CellMerge(int beginColumn, int beginCell, int endColumn, int endCell) { 19 | this.beginColumn = beginColumn; 20 | this.beginCell = beginCell; 21 | this.endColumn = endColumn; 22 | this.endCell = endCell; 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | StringBuffer sb = new StringBuffer(); 28 | sb.append(""); 33 | return sb.toString(); 34 | } 35 | 36 | public int getBeginColumn() { 37 | return beginColumn; 38 | } 39 | 40 | public void setBeginColumn(int beginColumn) { 41 | this.beginColumn = beginColumn; 42 | } 43 | 44 | public int getEndColumn() { 45 | return endColumn; 46 | } 47 | 48 | public void setEndColumn(int endColumn) { 49 | this.endColumn = endColumn; 50 | } 51 | 52 | public int getBeginCell() { 53 | return beginCell; 54 | } 55 | 56 | public void setBeginCell(int beginCell) { 57 | this.beginCell = beginCell; 58 | } 59 | 60 | public int getEndCell() { 61 | return endCell; 62 | } 63 | 64 | public void setEndCell(int endCell) { 65 | this.endCell = endCell; 66 | } 67 | } -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/util/FileUtils.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.util; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | import java.nio.file.Files; 9 | import java.nio.file.Paths; 10 | import java.util.Enumeration; 11 | import java.util.zip.ZipEntry; 12 | import java.util.zip.ZipFile; 13 | import java.util.zip.ZipOutputStream; 14 | 15 | /* 16 | * File name : FileUtils.java 17 | * @Copyright : luoyoub@163.com 18 | * Description : javaexcel 19 | * Author : Robert 20 | * CreateTime : 2016年4月7日 21 | */ 22 | public class FileUtils { 23 | @SuppressWarnings("unchecked") 24 | public static void substitute(String zipfile, String tmpfile, 25 | String entry, OutputStream out) throws IOException { 26 | ZipFile zip = new ZipFile(zipfile); 27 | ZipOutputStream zos = new ZipOutputStream(out); 28 | Enumeration en = (Enumeration) zip.entries(); 29 | while (en.hasMoreElements()) { 30 | ZipEntry ze = en.nextElement(); 31 | if (!ze.getName().equals(entry)) { 32 | zos.putNextEntry(new ZipEntry(ze.getName())); 33 | InputStream is = zip.getInputStream(ze); 34 | copyStream(is, zos); 35 | is.close(); 36 | } 37 | } 38 | zos.putNextEntry(new ZipEntry(entry)); 39 | InputStream is = new FileInputStream(tmpfile); 40 | copyStream(is, zos); 41 | zip.close(); 42 | is.close(); 43 | zos.close(); 44 | } 45 | 46 | /** 47 | * 校验fileName的父目录是否存在 48 | * 49 | * @param filePath 50 | * @return 51 | */ 52 | public static boolean isExistsOfParentDir(String filePath) { 53 | File file = new File(filePath); 54 | if (Files.notExists(Paths.get(file.getParent()))) { 55 | return true; 56 | } 57 | return false; 58 | } 59 | 60 | private static void copyStream(InputStream in, OutputStream out) 61 | throws IOException { 62 | byte[] chunk = new byte[1024]; 63 | int count; 64 | while ((count = in.read(chunk)) >= 0) { 65 | out.write(chunk, 0, count); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/model/ExcelTitle.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /* 7 | * File name : ExeclTitle.java 8 | * @Copyright : luoyoub@163.com 9 | * Description : javaexcel 10 | * Author : Robert 11 | * CreateTime : 2016年4月1日 12 | */ 13 | public class ExcelTitle { 14 | // 列索引 15 | private int index; 16 | 17 | // 列名 18 | private String name; 19 | 20 | // 设置列宽 21 | private int columnWidth; 22 | 23 | // 列标题 24 | private String displayName; 25 | 26 | private CellType dataType; 27 | 28 | // 列是否支持合并(行合并) 29 | private boolean isMerge = false; 30 | 31 | private ExcelCellStyle cellStyle = new ExcelCellStyle(); 32 | 33 | // 子标题列表 34 | private List subTitles = new ArrayList(); 35 | 36 | // 当单元格为空时填充字符 37 | private String fillChar = ""; 38 | 39 | public String getFillChar() { 40 | return fillChar; 41 | } 42 | 43 | public void setFillChar(String fillChar) { 44 | this.fillChar = fillChar; 45 | } 46 | 47 | public ExcelCellStyle getCellStyle() { 48 | return cellStyle; 49 | } 50 | 51 | public void setCellStyle(ExcelCellStyle cellStyle) { 52 | this.cellStyle = cellStyle; 53 | } 54 | 55 | public int getIndex() { 56 | return index; 57 | } 58 | 59 | public void setIndex(int index) { 60 | this.index = index; 61 | } 62 | 63 | public int getColumnWidth() { 64 | return columnWidth; 65 | } 66 | 67 | public void setColumnWidth(int columnWidth) { 68 | this.columnWidth = columnWidth; 69 | } 70 | 71 | public String getName() { 72 | return name; 73 | } 74 | 75 | public void setName(String name) { 76 | this.name = name; 77 | } 78 | 79 | public String getDisplayName() { 80 | return displayName; 81 | } 82 | 83 | public void setDisplayName(String displayName) { 84 | this.displayName = displayName; 85 | } 86 | 87 | public CellType getDataType() { 88 | return dataType; 89 | } 90 | 91 | public void setDataType(CellType dataType) { 92 | this.dataType = dataType; 93 | } 94 | 95 | public boolean isMerge() { 96 | return isMerge; 97 | } 98 | 99 | public void setMerge(boolean isMerge) { 100 | this.isMerge = isMerge; 101 | } 102 | 103 | public List getSubTitles() { 104 | return subTitles; 105 | } 106 | 107 | public void setSubTitles(List subTitles) { 108 | this.subTitles = subTitles; 109 | } 110 | } -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/model/ExcelMetaData.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.model; 2 | 3 | import java.util.List; 4 | 5 | /* 6 | * File name : ExeclInfo.java 7 | * @Copyright : luoyoub@163.com 8 | * Description : execlservice-common 9 | * Author : Robert 10 | * CreateTime : 2016年3月14日 11 | */ 12 | public class ExcelMetaData { 13 | // Excel文件名称 14 | private String fileName = "service"; 15 | 16 | // Excel sheet名称 17 | private String sheetName = "service"; 18 | 19 | // 是否有大表头 20 | private boolean hasHeader = false; 21 | 22 | // 大表头 23 | private ExcelHeader header; 24 | 25 | private boolean hasSubTitle = false; 26 | 27 | private ExcelCellStyle titleStyle; 28 | 29 | // 列标题 30 | private List excelTitle; 31 | 32 | // 是否有表底部备注栏 33 | private boolean hasFooter = false; 34 | 35 | // 备注 36 | private ExcelFooter footer; 37 | 38 | public ExcelCellStyle getTitleStyle() { 39 | return titleStyle; 40 | } 41 | 42 | public void setTitleStyle(ExcelCellStyle titleStyle) { 43 | this.titleStyle = titleStyle; 44 | } 45 | 46 | public String getFileName() { 47 | return fileName; 48 | } 49 | 50 | public void setFileName(String fileName) { 51 | this.fileName = fileName; 52 | } 53 | 54 | public boolean isHasSubTitle() { 55 | return hasSubTitle; 56 | } 57 | 58 | public void setHasSubTitle(boolean hasSubTitle) { 59 | this.hasSubTitle = hasSubTitle; 60 | } 61 | 62 | public String getSheetName() { 63 | return sheetName; 64 | } 65 | 66 | public void setSheetName(String sheetName) { 67 | this.sheetName = sheetName; 68 | } 69 | 70 | public boolean isHasHeader() { 71 | return hasHeader; 72 | } 73 | 74 | public void setHasHeader(boolean hasHeader) { 75 | this.hasHeader = hasHeader; 76 | } 77 | 78 | public ExcelHeader getHeader() { 79 | return header; 80 | } 81 | 82 | public void setHeader(ExcelHeader header) { 83 | this.header = header; 84 | } 85 | 86 | public List getExcelTitle() { 87 | return excelTitle; 88 | } 89 | 90 | public void setExcelTitle(List excelTitle) { 91 | this.excelTitle = excelTitle; 92 | } 93 | 94 | public boolean isHasFooter() { 95 | return hasFooter; 96 | } 97 | 98 | public void setHasFooter(boolean hasFooter) { 99 | this.hasFooter = hasFooter; 100 | } 101 | 102 | public ExcelFooter getFooter() { 103 | return footer; 104 | } 105 | 106 | public void setFooter(ExcelFooter footer) { 107 | this.footer = footer; 108 | } 109 | } -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/model/ExcelColor.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.model; 2 | 3 | import org.apache.poi.ss.usermodel.IndexedColors; 4 | import org.apache.poi.xssf.usermodel.XSSFFont; 5 | 6 | /* 7 | * File name : ExcelColor.java 8 | * @Copyright : luoyoub@163.com 9 | * Description : javaexcel 10 | * Author : Robert 11 | * CreateTime : 2016年4月5日 12 | */ 13 | public interface ExcelColor { 14 | short DEFAULT_COLOR = XSSFFont.DEFAULT_FONT_COLOR; 15 | 16 | short BLACK = IndexedColors.BLACK.index; 17 | 18 | short WHITE = IndexedColors.WHITE.index; 19 | 20 | short RED = IndexedColors.RED.index; 21 | 22 | short BRIGHT_GREEN = IndexedColors.BRIGHT_GREEN.index; 23 | 24 | short BLUE = IndexedColors.BLUE.index; 25 | 26 | short YELLOW = IndexedColors.YELLOW.index; 27 | 28 | short PINK = IndexedColors.PINK.index; 29 | 30 | short TURQUOISE = IndexedColors.TURQUOISE.index; 31 | 32 | short DARK_RED = IndexedColors.DARK_RED.index; 33 | 34 | short GREEN = IndexedColors.GREEN.index; 35 | 36 | short DARK_BLUE = IndexedColors.DARK_BLUE.index; 37 | 38 | short DARK_YELLOW = IndexedColors.DARK_YELLOW.index; 39 | 40 | short VIOLET = IndexedColors.VIOLET.index; 41 | 42 | short TEAL = IndexedColors.TEAL.index; 43 | 44 | short GREY_25_PERCENT = IndexedColors.GREY_25_PERCENT.index; 45 | 46 | short GREY_50_PERCENT = IndexedColors.GREY_50_PERCENT.index; 47 | 48 | short CORNFLOWER_BLUE = IndexedColors.CORNFLOWER_BLUE.index; 49 | 50 | short MAROON = IndexedColors.MAROON.index; 51 | 52 | short LEMON_CHIFFON = IndexedColors.LEMON_CHIFFON.index; 53 | 54 | short ORCHID = IndexedColors.ORCHID.index; 55 | 56 | short CORAL = IndexedColors.CORAL.index; 57 | 58 | short ROYAL_BLUE = IndexedColors.ROYAL_BLUE.index; 59 | 60 | short LIGHT_CORNFLOWER_BLUE = IndexedColors.LIGHT_CORNFLOWER_BLUE.index; 61 | 62 | short SKY_BLUE = IndexedColors.SKY_BLUE.index; 63 | 64 | short LIGHT_TURQUOISE = IndexedColors.LIGHT_TURQUOISE.index; 65 | 66 | short LIGHT_GREEN = IndexedColors.LIGHT_GREEN.index; 67 | 68 | short LIGHT_YELLOW = IndexedColors.LIGHT_YELLOW.index; 69 | 70 | short PALE_BLUE = IndexedColors.PALE_BLUE.index; 71 | 72 | short ROSE = IndexedColors.ROSE.index; 73 | 74 | short LAVENDER = IndexedColors.LAVENDER.index; 75 | 76 | short TAN = IndexedColors.TAN.index; 77 | 78 | short LIGHT_BLUE = IndexedColors.LIGHT_BLUE.index; 79 | 80 | short AQUA = IndexedColors.AQUA.index; 81 | 82 | short LIME = IndexedColors.LIME.index; 83 | 84 | short GOLD = IndexedColors.GOLD.index; 85 | 86 | short LIGHT_ORANGE = IndexedColors.LIGHT_ORANGE.index; 87 | 88 | short ORANGE = IndexedColors.ORANGE.index; 89 | 90 | short BLUE_GREY = IndexedColors.BLUE_GREY.index; 91 | 92 | short GREY_40_PERCENT = IndexedColors.GREY_40_PERCENT.index; 93 | 94 | short DARK_TEAL = IndexedColors.DARK_TEAL.index; 95 | 96 | short SEA_GREEN = IndexedColors.SEA_GREEN.index; 97 | 98 | short DARK_GREEN = IndexedColors.DARK_GREEN.index; 99 | 100 | short OLIVE_GREEN = IndexedColors.OLIVE_GREEN.index; 101 | 102 | short BROWN = IndexedColors.BROWN.index; 103 | 104 | short PLUM = IndexedColors.PLUM.index; 105 | 106 | short INDIGO = IndexedColors.INDIGO.index; 107 | 108 | short GREY_80_PERCENT = IndexedColors.GREY_80_PERCENT.index; 109 | 110 | short AUTOMATIC = IndexedColors.AUTOMATIC.index; 111 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | org.javaexcel 5 | javaexcel 6 | 0.0.3 7 | 8 | 9 | UTF-8 10 | UTF-8 11 | 1.8 12 | 1.8 13 | true 14 | true 15 | UTF-8 16 | 3.14 17 | 4.11 18 | 19 | 20 | 21 | 22 | org.apache.poi 23 | poi 24 | ${poi.version} 25 | 26 | 27 | org.apache.poi 28 | poi-ooxml 29 | ${poi.version} 30 | 31 | 32 | org.apache.poi 33 | poi-ooxml-schemas 34 | ${poi.version} 35 | 36 | 37 | 38 | junit 39 | junit 40 | ${junit.version} 41 | test 42 | 43 | 44 | 45 | com.google.code.gson 46 | gson 47 | 2.4 48 | compile 49 | 50 | 51 | 52 | 53 | 54 | 55 | maven-resources-plugin 56 | 57 | 58 | copy-resources 59 | 60 | generate-test-sources 61 | 62 | copy-resources 63 | 64 | 65 | ${basedir}/target/test-classes 66 | 67 | 68 | src/main/resources 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | org.apache.maven.plugins 78 | maven-assembly-plugin 79 | 80 | 81 | assembly.xml 82 | 83 | 84 | 85 | 86 | make-assembly 87 | package 88 | 89 | single 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/ExcelWriter.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import org.apache.poi.ss.usermodel.Cell; 9 | import org.apache.poi.ss.usermodel.CellStyle; 10 | import org.apache.poi.ss.usermodel.DataFormat; 11 | import org.apache.poi.ss.usermodel.Font; 12 | import org.apache.poi.ss.usermodel.Row; 13 | import org.apache.poi.ss.usermodel.Sheet; 14 | import org.apache.poi.ss.usermodel.Workbook; 15 | import org.javaexcel.model.ExcelCellStyle; 16 | import org.javaexcel.model.ExcelFooter; 17 | import org.javaexcel.model.ExcelHeader; 18 | import org.javaexcel.model.ExcelMetaData; 19 | import org.javaexcel.model.ExcelTitle; 20 | 21 | /* 22 | * File name : ExcelWriter.java 23 | * @Copyright : luoyoub@163.com 24 | * Description : javaexcel 25 | * Author : Robert 26 | * CreateTime : 2016年4月1日 27 | */ 28 | public abstract class ExcelWriter { 29 | protected static final short DEFAULTROWHEIGHT = 16; 30 | // 样式表 31 | protected Map stylesMap = new HashMap(); 32 | // 存储所有的标题(子级标题) 33 | protected List allTitles = new ArrayList(); 34 | protected List allDatas = new ArrayList(); 35 | protected int rownum = 0; 36 | protected int columnSize = 0; 37 | protected Workbook wb; 38 | protected Sheet sheet; 39 | protected CellStyle cellStyle; 40 | protected Font font; 41 | protected Row row; 42 | protected Cell cell; 43 | protected ExcelMetaData metedata; 44 | protected DataFormat datafmt; 45 | 46 | /** 47 | * 导出数据到EXCEL 48 | * 49 | * @param metadata 50 | * @param datas 51 | * @param filePath 52 | * @return 53 | */ 54 | public abstract boolean process(ExcelMetaData metedata, List datas, String fileName) throws Exception; 55 | 56 | protected void init() throws Exception { 57 | List titles = this.metedata.getExcelTitle(); 58 | if (null == titles || titles.isEmpty()) { 59 | throw new Exception("The excel title is empty."); 60 | } 61 | for (ExcelTitle excelTitle : titles) { 62 | if (null != excelTitle.getSubTitles() && !excelTitle.getSubTitles().isEmpty()) { 63 | // 列设置不允许既需要合并单元格又有子标题 64 | if (excelTitle.isMerge()) { 65 | throw new Exception("The column has sub title that cannot merge the cell."); 66 | } 67 | 68 | allTitles.addAll(excelTitle.getSubTitles()); 69 | columnSize += excelTitle.getSubTitles().size(); 70 | continue; 71 | } 72 | allTitles.add(excelTitle); 73 | columnSize++; 74 | } 75 | } 76 | 77 | protected void initStyle() { 78 | // 设置表头样式 79 | ExcelHeader header = metedata.getHeader(); 80 | if (metedata.isHasHeader() && null != header) { 81 | setCellStyle(header.getCellStyle()); 82 | this.stylesMap.put("headerStyle", cellStyle); 83 | } 84 | 85 | // 设置footer样式 86 | ExcelFooter footer = metedata.getFooter(); 87 | if (metedata.isHasFooter() && null != footer) { 88 | setCellStyle(footer.getCellStyle()); 89 | this.stylesMap.put("footerStyle", cellStyle); 90 | } 91 | 92 | // 设置标题样式 93 | this.setCellStyle(metedata.getTitleStyle()); 94 | stylesMap.put("titleStyle", cellStyle); 95 | 96 | // 设置数据单元格样式 97 | for (ExcelTitle excelTitle : allTitles) { 98 | this.setCellStyle(excelTitle.getCellStyle()); 99 | setDataFormat(excelTitle); 100 | stylesMap.put("cellstyle_" + excelTitle.getIndex(), cellStyle); 101 | } 102 | } 103 | 104 | private void setCellStyle(ExcelCellStyle style) { 105 | cellStyle = wb.createCellStyle(); 106 | cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); 107 | if (null != style) { 108 | cellStyle.setAlignment(style.getAlign()); 109 | cellStyle.setVerticalAlignment(style.getVerticalAlign()); 110 | font = wb.createFont(); 111 | font.setFontHeightInPoints(style.getSize()); 112 | font.setColor(style.getColor()); 113 | font.setItalic(style.isItalic()); 114 | cellStyle.setFont(font); 115 | cellStyle.setFillForegroundColor(style.getBackgroundColor()); 116 | cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND); 117 | } 118 | setBorder(); 119 | } 120 | 121 | private void setDataFormat(ExcelTitle ete) { 122 | datafmt = wb.createDataFormat(); 123 | switch (ete.getDataType()) { 124 | case NUMBER: 125 | this.cellStyle.setDataFormat(datafmt.getFormat("###.00")); 126 | break; 127 | case INT: 128 | this.cellStyle.setDataFormat(datafmt.getFormat("0")); 129 | break; 130 | case MONEY: 131 | this.cellStyle.setDataFormat(datafmt.getFormat("¥#,##0.00")); 132 | break; 133 | case PERCENT: 134 | this.cellStyle.setDataFormat(datafmt.getFormat("00.00%")); 135 | break; 136 | default: 137 | break; 138 | } 139 | } 140 | 141 | /** 142 | * 获取样式 143 | * 144 | * @param key 145 | * @return 146 | */ 147 | protected CellStyle getStyle(String key) { 148 | return stylesMap.get(key); 149 | } 150 | 151 | /** 152 | * 设置边框 153 | */ 154 | protected void setBorder() { 155 | if (null != this.cellStyle) { 156 | cellStyle.setBorderBottom(CellStyle.BORDER_THIN); 157 | cellStyle.setBorderTop(CellStyle.BORDER_THIN); 158 | cellStyle.setBorderRight(CellStyle.BORDER_THIN); 159 | cellStyle.setBorderLeft(CellStyle.BORDER_THIN); 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /src/test/java/org/javaexcel/xlsx/SimpleReportExportTest.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.xlsx; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.List; 6 | 7 | import org.apache.poi.xssf.usermodel.XSSFCellStyle; 8 | import org.javaexcel.ExcelWriter; 9 | import org.javaexcel.ExcelWriterFactory; 10 | import org.javaexcel.model.CellType; 11 | import org.javaexcel.model.ExcelCellStyle; 12 | import org.javaexcel.model.ExcelColor; 13 | import org.javaexcel.model.ExcelHeader; 14 | import org.javaexcel.model.ExcelMetaData; 15 | import org.javaexcel.model.ExcelTitle; 16 | import org.javaexcel.model.ExcelType; 17 | import org.junit.Before; 18 | import org.junit.Test; 19 | 20 | /* 21 | * File name : SimpleReportExportTest.java 22 | * @Copyright : luoyoub@163.com 23 | * Description : javaexcel 24 | * Author : Robert 25 | * CreateTime : 2016年4月6日 26 | */ 27 | public class SimpleReportExportTest { 28 | private static final int ROWS = 10; 29 | private ExcelMetaData metadata; 30 | private List datas; 31 | 32 | @Test 33 | public void test() { 34 | long begTime = System.currentTimeMillis(); 35 | try { 36 | ExcelWriter writer = ExcelWriterFactory.getWriter(ExcelType.XLS); 37 | writer.process(metadata, datas, "/Users/Robert/Desktop/QA_test/user.xls"); 38 | } catch (Exception e) { 39 | e.printStackTrace(); 40 | } 41 | 42 | System.out.println("Total:" + (System.currentTimeMillis() - begTime) + "ms"); 43 | } 44 | 45 | @Before 46 | public void setUp() throws Exception { 47 | metadata = new ExcelMetaData(); 48 | metadata.setFileName("SimpleReport"); 49 | metadata.setSheetName("SimpleReport"); 50 | 51 | // 设置大表头 52 | this.metadata.setHasHeader(true); 53 | ExcelHeader header = new ExcelHeader(); 54 | header.setHeaderName("报表"); 55 | ExcelCellStyle hs = new ExcelCellStyle(); 56 | hs.setAlign(XSSFCellStyle.ALIGN_CENTER); 57 | hs.setVerticalAlign(XSSFCellStyle.ALIGN_CENTER); 58 | hs.setSize((short) 42); 59 | hs.setColor(ExcelColor.BLACK); 60 | header.setCellStyle(hs); 61 | this.metadata.setHeader(header); 62 | 63 | // 初始化数据 64 | structureMetaData(); 65 | constructdata(); 66 | } 67 | 68 | /** 69 | * 70 | */ 71 | private void constructdata() { 72 | this.datas = new ArrayList(); 73 | User user = null; 74 | for (int i = 0; i < ROWS; i++) { 75 | user = new User(i + 1, "张晓明" + i, new Date(), "18913538888", "上海市浦东新区康桥御桥路200号", 0.45); 76 | this.datas.add(user); 77 | } 78 | } 79 | 80 | /** 81 | * 82 | */ 83 | private void structureMetaData() { 84 | // 设置表头 85 | List titles = new ArrayList(); 86 | int rownum = 0; 87 | 88 | ExcelTitle t1 = new ExcelTitle(); 89 | t1.setIndex(rownum++); 90 | t1.setName("id"); 91 | t1.setDisplayName("ID"); 92 | t1.setDataType(CellType.INT); 93 | t1.setColumnWidth(8); 94 | titles.add(t1); 95 | 96 | ExcelTitle t2 = new ExcelTitle(); 97 | t2.setIndex(rownum++); 98 | t2.setName("name"); 99 | t2.setDisplayName("姓名"); 100 | t2.setDataType(CellType.TEXT); 101 | t2.setColumnWidth(10); 102 | titles.add(t2); 103 | 104 | ExcelTitle t3 = new ExcelTitle(); 105 | t3.setIndex(rownum++); 106 | t3.setName("birthday"); 107 | t3.setDisplayName("出生日期"); 108 | t3.setColumnWidth(20); 109 | t3.setDataType(CellType.DATE); 110 | titles.add(t3); 111 | 112 | ExcelTitle t4 = new ExcelTitle(); 113 | t4.setIndex(rownum++); 114 | t4.setName("telphone"); 115 | t4.setDisplayName("电话"); 116 | t4.setDataType(CellType.TEXT); 117 | t4.setColumnWidth(15); 118 | titles.add(t4); 119 | 120 | ExcelTitle t5 = new ExcelTitle(); 121 | t5.setIndex(rownum++); 122 | t5.setName("address"); 123 | t5.setDisplayName("联系地址"); 124 | t5.setDataType(CellType.TEXT); 125 | t5.setColumnWidth(55); 126 | titles.add(t5); 127 | 128 | ExcelTitle t6 = new ExcelTitle(); 129 | t6.setIndex(rownum++); 130 | t6.setName("percent"); 131 | t6.setDisplayName("联系地址"); 132 | t6.setDataType(CellType.PERCENT); 133 | t6.setColumnWidth(55); 134 | titles.add(t6); 135 | 136 | this.metadata.setExcelTitle(titles); 137 | this.metadata.setHasSubTitle(false); 138 | } 139 | 140 | class User { 141 | private Integer id; 142 | private String name; 143 | private Date birthday; 144 | private String telphone; 145 | private String address; 146 | private double percent; 147 | 148 | public double getPercent() { 149 | return percent; 150 | } 151 | 152 | public void setPercent(double percent) { 153 | this.percent = percent; 154 | } 155 | 156 | /** 157 | * @param id 158 | * @param name 159 | * @param birthday 160 | * @param telphone 161 | * @param address 162 | */ 163 | public User(Integer id, String name, Date birthday, String telphone, String address, double percent) { 164 | super(); 165 | this.id = id; 166 | this.name = name; 167 | this.birthday = birthday; 168 | this.telphone = telphone; 169 | this.address = address; 170 | this.percent = percent; 171 | } 172 | 173 | public Integer getId() { 174 | return id; 175 | } 176 | 177 | public void setId(Integer id) { 178 | this.id = id; 179 | } 180 | 181 | public String getName() { 182 | return name; 183 | } 184 | 185 | public void setName(String name) { 186 | this.name = name; 187 | } 188 | 189 | public Date getBirthday() { 190 | return birthday; 191 | } 192 | 193 | public void setBirthday(Date birthday) { 194 | this.birthday = birthday; 195 | } 196 | 197 | public String getTelphone() { 198 | return telphone; 199 | } 200 | 201 | public void setTelphone(String telphone) { 202 | this.telphone = telphone; 203 | } 204 | 205 | public String getAddress() { 206 | return address; 207 | } 208 | 209 | public void setAddress(String address) { 210 | this.address = address; 211 | } 212 | } 213 | } -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/xlsx/SpreadSheetWriter.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.xlsx; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | 6 | import org.apache.poi.hssf.util.CellReference; 7 | import org.javaexcel.model.CellMerge; 8 | 9 | /* 10 | * File name : SpreadSheetWriter.java 11 | * @Copyright : luoyoub@163.com 12 | * Description : javaexcel 13 | * Author : Robert 14 | * CreateTime : 2016年4月2日 15 | */ 16 | public class SpreadSheetWriter { 17 | // XML Encode 18 | private static final String[] xmlCode = new String[256]; 19 | private Writer _out; 20 | private int _rownum; 21 | private static String LINE_SEPARATOR = System.getProperty("line.separator"); 22 | 23 | static { 24 | // Special characters 25 | xmlCode['\''] = "'"; 26 | // double quote 27 | xmlCode['\"'] = "\""; 28 | // ampersand 29 | xmlCode['&'] = "&"; 30 | // lower than 31 | xmlCode['<'] = "<"; 32 | // greater than 33 | xmlCode['>'] = ">"; 34 | } 35 | 36 | public SpreadSheetWriter(Writer out) { 37 | _out = out; 38 | } 39 | 40 | public void beginSheet() throws IOException { 41 | _out.write(""); 42 | _out.write("" + LINE_SEPARATOR); 43 | } 44 | 45 | public void endSheet() throws IOException { 46 | _out.write(""); 47 | } 48 | 49 | public void beginSheetData() throws IOException { 50 | _out.write("" + LINE_SEPARATOR); 51 | } 52 | 53 | public void endSheetData() throws IOException { 54 | _out.write(""); 55 | } 56 | 57 | /** 58 | * 插入新行 59 | * 60 | * @param rownum(以0开始) 61 | */ 62 | public void insertRow(int rownum) throws IOException { 63 | _out.write("" + LINE_SEPARATOR); 64 | this._rownum = rownum; 65 | } 66 | 67 | /** 68 | * 插入行且设置高度 69 | * 70 | * @param rownum(以0开始) 71 | * @param columnNum 72 | * @param height 73 | * @throws IOException 74 | */ 75 | public void insertRowWithHeight(int rownum, int columnNum, double height) throws IOException { 76 | this._out.write("" + LINE_SEPARATOR); 78 | this._rownum = rownum; 79 | } 80 | 81 | /** 82 | * 插入行结束标志 83 | */ 84 | public void endRow() throws IOException { 85 | _out.write("" + LINE_SEPARATOR); 86 | } 87 | 88 | /** 89 | * 开始设置列宽 90 | * 91 | * @throws IOException 92 | */ 93 | public void beginSetColWidth() throws IOException { 94 | this._out.write("" + LINE_SEPARATOR); 95 | } 96 | 97 | /** 98 | * 设置列宽下标从0开始 99 | * 100 | * @param columnIndex 101 | * @param columnWidth 102 | * @throws IOException 103 | */ 104 | public void setColWidthBeforeSheet(int columnIndex, double columnWidth) throws IOException { 105 | this._out.write("" + LINE_SEPARATOR); 108 | } 109 | 110 | /** 111 | * 设置列宽结束 112 | * 113 | * @throws IOException 114 | */ 115 | public void endSetColWidth() throws IOException { 116 | this._out.write("" + LINE_SEPARATOR); 117 | } 118 | 119 | /** 120 | * 合并单元格开始标记 121 | * 122 | * @throws IOException 123 | */ 124 | public void beginMergerCell(int count) throws IOException { 125 | this._out.write("" + LINE_SEPARATOR); 126 | } 127 | 128 | /** 129 | * 合并单元格(下标从0开始) 130 | * 131 | * @param beginColumn 132 | * @param beginCell 133 | * @param endColumn 134 | * @param endCell 135 | * @throws IOException 136 | */ 137 | public void setMergeCell(int beginColumn, int beginCell, int endColumn, 138 | int endCell) throws IOException { 139 | this._out.write("" + LINE_SEPARATOR); 142 | } 143 | 144 | public void setMergeCell(CellMerge mergeCell) throws IOException { 145 | _out.write(mergeCell.toString()); 146 | } 147 | 148 | /** 149 | * 合并单元格结束标记 150 | * 151 | * @throws IOException 152 | */ 153 | public void endMergerCell() throws IOException { 154 | this._out.write("" + LINE_SEPARATOR); 155 | } 156 | 157 | /** 158 | * 插入新列 159 | * 160 | * @param columnIndex 161 | * @param value 162 | * @param styleIndex 163 | * @throws IOException 164 | */ 165 | public void createCell(int columnIndex, String value, int styleIndex) 166 | throws IOException { 167 | String ref = new CellReference(_rownum, columnIndex).formatAsString(); 168 | _out.write(""); 173 | if (null != value) { 174 | _out.write("" + value + ""); 175 | } else { 176 | _out.write(""); 177 | } 178 | 179 | _out.write(""); 180 | } 181 | 182 | /** 183 | * 插入一个Cell(包含值) 184 | * 185 | * @param columnIndex 186 | * @param value 187 | * @throws IOException 188 | */ 189 | public void createCell(int columnIndex, String value) 190 | throws IOException { 191 | createCell(columnIndex, value, -1); 192 | } 193 | 194 | /** 195 | * 插入一个Cell(不包含值,合并单元格) 196 | * 197 | * @param columnIndex 198 | * @throws IOException 199 | */ 200 | public void createCell(int columnIndex, int styleIndex) throws IOException { 201 | String ref = new CellReference(_rownum, columnIndex).formatAsString(); 202 | _out.write(""); 203 | } 204 | 205 | /** 206 | *

207 | * Encode the given text into xml. 208 | *

209 | * 210 | * @param string 211 | * the text to encode 212 | * @return the encoded string 213 | */ 214 | public static String encoderXML(String string) { 215 | if (string == null) { 216 | return ""; 217 | } 218 | int n = string.length(); 219 | char character; 220 | String xmlchar; 221 | StringBuffer buffer = new StringBuffer(); 222 | // loop over all the characters of the String. 223 | for (int i = 0; i < n; i++) { 224 | character = string.charAt(i); 225 | try { 226 | xmlchar = xmlCode[character]; 227 | if (xmlchar == null) { 228 | buffer.append(character); 229 | } else { 230 | buffer.append(xmlCode[character]); 231 | } 232 | } catch (ArrayIndexOutOfBoundsException aioobe) { 233 | buffer.append(character); 234 | } 235 | } 236 | return buffer.toString(); 237 | } 238 | } -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/xls/DataToExcelWriter.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.xls; 2 | 3 | import java.io.FileOutputStream; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import org.apache.poi.hssf.usermodel.HSSFWorkbook; 9 | import org.apache.poi.ss.usermodel.CellStyle; 10 | import org.apache.poi.ss.usermodel.Row; 11 | import org.apache.poi.ss.util.CellRangeAddress; 12 | import org.apache.poi.ss.util.CellUtil; 13 | import org.apache.poi.ss.util.RegionUtil; 14 | import org.apache.poi.xssf.usermodel.XSSFWorkbook; 15 | import org.javaexcel.ExcelWriter; 16 | import org.javaexcel.model.ExcelMetaData; 17 | import org.javaexcel.model.ExcelTitle; 18 | import org.javaexcel.util.Const; 19 | import org.javaexcel.util.FileUtils; 20 | import org.javaexcel.util.JsonUtil; 21 | 22 | /* 23 | * File name : ExcelWriterImpl.java 24 | * @Copyright : luoyoub@163.com 25 | * Description : javaexcel 26 | * Author : Robert 27 | * CreateTime : 2016年4月6日 28 | */ 29 | public class DataToExcelWriter extends ExcelWriter { 30 | // 存储大标题 31 | private List bigheaders = new ArrayList(); 32 | 33 | // 存储无子标题的Title 34 | private List mergeTitles = new ArrayList(); 35 | private List cellRanges = new ArrayList(); 36 | 37 | @Override 38 | public boolean process(ExcelMetaData metedata, List datas, 39 | String fileName) throws Exception { 40 | this.metedata = metedata; 41 | this.allDatas.addAll(datas); 42 | boolean result = false; 43 | 44 | // 校验fileName的父目录是否存在 45 | if (FileUtils.isExistsOfParentDir(fileName)) { 46 | throw new Exception("Output directory does not exist."); 47 | } 48 | 49 | try (FileOutputStream out = new FileOutputStream(fileName)) { 50 | initWorkbook(fileName); 51 | sheet = wb.createSheet(this.metedata.getSheetName()); 52 | 53 | init(); 54 | initStyle(); 55 | 56 | // 写大表头 57 | writeHeader(); 58 | 59 | // 写表头 60 | writeTitle(); 61 | 62 | // 写数据 63 | writeData(); 64 | 65 | writeFooter(); 66 | 67 | setAllRangeBorder(); 68 | 69 | wb.write(out); 70 | wb.close(); 71 | result = true; 72 | } catch (Exception e) { 73 | throw e; 74 | } 75 | return result; 76 | } 77 | 78 | /** 79 | * 获取 Workbook 80 | */ 81 | public void initWorkbook(String fileName) { 82 | if (fileName.toLowerCase().endsWith(Const.EXCEL_SUFFIX_XLS)) { 83 | wb = new HSSFWorkbook(); 84 | } else { 85 | wb = new XSSFWorkbook(); 86 | } 87 | } 88 | 89 | private void writeHeader() { 90 | if (this.metedata.isHasHeader() && null != this.metedata.getHeader()) { 91 | cellStyle = this.getStyle("headerStyle"); 92 | row = sheet.createRow(rownum); 93 | CellRangeAddress address = new CellRangeAddress(rownum, rownum, 0, columnSize - 1); 94 | sheet.addMergedRegion(address); 95 | cellRanges.add(address); 96 | row.setHeightInPoints(metedata.getHeader().getRowHeight()); 97 | 98 | CellUtil.createCell(row, rownum, metedata.getHeader().getHeaderName(), cellStyle); 99 | rownum++; 100 | } 101 | } 102 | 103 | private void writeFooter() { 104 | if (this.metedata.isHasFooter() && null != this.metedata.getFooter()) { 105 | cellStyle = this.getStyle("footerStyle"); 106 | row = sheet.createRow(rownum); 107 | CellRangeAddress address = new CellRangeAddress(rownum, rownum, 0, columnSize - 1); 108 | sheet.addMergedRegion(address); 109 | cellRanges.add(address); 110 | row.setHeightInPoints(metedata.getFooter().getRowHeight()); 111 | CellUtil.createCell(row, 0, metedata.getFooter().getRemarks(), cellStyle); 112 | } 113 | } 114 | 115 | /** 116 | * 117 | */ 118 | private void setAllRangeBorder() { 119 | for (CellRangeAddress address : this.cellRanges) { 120 | this.setBorder(address); 121 | } 122 | } 123 | 124 | private void writeTitle() { 125 | if (null == metedata.getExcelTitle() || metedata.getExcelTitle().isEmpty()) { 126 | return; 127 | } 128 | 129 | cellStyle = this.getStyle("titleStyle"); 130 | if (metedata.isHasSubTitle() && null != this.metedata.getExcelTitle() && !this.metedata.getExcelTitle().isEmpty()) { 131 | List titles = metedata.getExcelTitle(); 132 | CellRangeAddress address = null; 133 | for (ExcelTitle ex : titles) { 134 | if (null != ex.getSubTitles() && ex.getSubTitles().size() >= 2) { 135 | address = new CellRangeAddress(rownum, rownum, ex.getSubTitles().get(0).getIndex(), ex.getSubTitles().get(ex.getSubTitles().size() - 1).getIndex()); 136 | 137 | sheet.addMergedRegion(address); 138 | cellRanges.add(address); 139 | bigheaders.add(ex); 140 | continue; 141 | } 142 | 143 | // 合并头两行的某一列 144 | address = new CellRangeAddress(rownum, rownum + 1, ex.getIndex(), ex.getIndex()); 145 | sheet.addMergedRegion(address); 146 | cellRanges.add(address); 147 | mergeTitles.add(ex); 148 | } 149 | 150 | // 写Excel表头 151 | Row oneRow = sheet.createRow(rownum++); 152 | oneRow.setHeightInPoints(DEFAULTROWHEIGHT); 153 | Row twoRow = sheet.createRow(rownum++); 154 | twoRow.setHeightInPoints(DEFAULTROWHEIGHT); 155 | for (ExcelTitle ete : titles) { 156 | if (null != ete.getSubTitles() && ete.getSubTitles().size() >= 2) { 157 | CellUtil.createCell(oneRow, ete.getSubTitles().get(0).getIndex(), ete.getDisplayName(), cellStyle); 158 | for (ExcelTitle subTitle : ete.getSubTitles()) { 159 | createCell(twoRow, subTitle); 160 | } 161 | } else { 162 | createCell(oneRow, ete); 163 | } 164 | } 165 | } else { 166 | row = sheet.createRow(rownum++); 167 | row.setHeightInPoints(DEFAULTROWHEIGHT); 168 | for (ExcelTitle eh : this.metedata.getExcelTitle()) { 169 | CellUtil.createCell(row, eh.getIndex(), eh.getDisplayName(), cellStyle); 170 | } 171 | } 172 | } 173 | 174 | private void createCell(Row row, ExcelTitle ete) { 175 | if (ete.getColumnWidth() > 0) { 176 | sheet.setColumnWidth(ete.getIndex(), ete.getColumnWidth() * 256); 177 | } else { 178 | sheet.setColumnWidth(ete.getIndex(), ete.getDisplayName().length() * 4 * 256); 179 | } 180 | CellUtil.createCell(row, ete.getIndex(), ete.getDisplayName(), cellStyle); 181 | } 182 | 183 | @SuppressWarnings({ "unchecked", "rawtypes" }) 184 | private void writeData() { 185 | for (Object object : allDatas) { 186 | Map dataMap = JsonUtil.stringToBean(JsonUtil.beanToString(object), Map.class); 187 | if (null == dataMap || dataMap.isEmpty()) { 188 | continue; 189 | } 190 | 191 | int rowsize = getColumns(dataMap); 192 | int maxRow = rownum + rowsize - 1; 193 | if (rowsize > 0) { 194 | // 需要处理行的数据合并 195 | for (ExcelTitle ex : mergeTitles) { 196 | CellRangeAddress address = new CellRangeAddress(rownum, maxRow, ex.getIndex(), ex.getIndex()); 197 | cellRanges.add(address); 198 | sheet.addMergedRegion(address); 199 | } 200 | 201 | row = sheet.createRow(rownum++); 202 | row.setHeightInPoints(DEFAULTROWHEIGHT); 203 | for (ExcelTitle eh : mergeTitles) { 204 | createCell(eh, dataMap.get(eh.getName())); 205 | } 206 | 207 | for (int i = 0; i < rowsize; i++) { 208 | for (ExcelTitle ele : bigheaders) { 209 | Object obj = dataMap.get(ele.getName()); 210 | if (obj instanceof List) { 211 | Map detailData = (Map) ((List) obj).get(i); 212 | ele.getSubTitles().stream().forEach(exte -> { 213 | createCell(exte, detailData.get(exte.getName())); 214 | }); 215 | } 216 | } 217 | 218 | // 最后一次循环需要处理迭代索引 219 | if (i != rowsize - 1) { 220 | row = sheet.createRow(rownum++); 221 | row.setHeightInPoints(DEFAULTROWHEIGHT); 222 | } 223 | } 224 | } else { 225 | row = sheet.createRow(rownum++); 226 | row.setHeightInPoints(DEFAULTROWHEIGHT); 227 | createAllCell(row, dataMap); 228 | } 229 | } 230 | } 231 | 232 | private void createCell(ExcelTitle ete, Object obj) { 233 | cellStyle = this.getStyle("cellstyle_" + ete.getIndex()); 234 | String result = ""; 235 | if (JsonUtil.isEmpty(obj)) { 236 | if (!JsonUtil.isEmpty(ete.getFillChar())) { 237 | result = ete.getFillChar(); 238 | } 239 | 240 | CellUtil.createCell(row, ete.getIndex(), result, cellStyle); 241 | return; 242 | } 243 | 244 | cell = row.createCell(ete.getIndex()); 245 | switch (ete.getDataType()) { 246 | case INT: 247 | case NUMBER: 248 | case MONEY: 249 | case PERCENT: 250 | cell.setCellValue(Double.valueOf(obj.toString())); 251 | break; 252 | default: 253 | result = obj.toString(); 254 | cell.setCellValue(result); 255 | break; 256 | } 257 | cell.setCellStyle(cellStyle); 258 | } 259 | 260 | private void createAllCell(Row row, Map data) { 261 | allTitles.stream().forEach(eh -> { 262 | createCell(eh, data.get(eh.getName())); 263 | }); 264 | } 265 | 266 | @SuppressWarnings("rawtypes") 267 | private static int getColumns(Map dataMap) { 268 | for (Object obj : dataMap.values()) { 269 | if (obj instanceof List) { 270 | return ((List) obj).size(); 271 | } 272 | } 273 | return 0; 274 | } 275 | 276 | public void setBorder(CellRangeAddress cellRangeAddress) { 277 | RegionUtil.setBorderLeft(CellStyle.BORDER_THIN, cellRangeAddress, sheet, wb); 278 | RegionUtil.setBorderBottom(CellStyle.BORDER_THIN, cellRangeAddress, sheet, wb); 279 | RegionUtil.setBorderRight(CellStyle.BORDER_THIN, cellRangeAddress, sheet, wb); 280 | RegionUtil.setBorderTop(CellStyle.BORDER_THIN, cellRangeAddress, sheet, wb); 281 | } 282 | } -------------------------------------------------------------------------------- /src/test/java/org/javaexcel/xlsx/XmlToExcelWriterTest.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.xlsx; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import org.apache.poi.ss.usermodel.CellStyle; 9 | import org.apache.poi.xssf.usermodel.XSSFCellStyle; 10 | import org.javaexcel.ExcelWriter; 11 | import org.javaexcel.ExcelWriterFactory; 12 | import org.javaexcel.model.CellType; 13 | import org.javaexcel.model.ExcelCellStyle; 14 | import org.javaexcel.model.ExcelColor; 15 | import org.javaexcel.model.ExcelFooter; 16 | import org.javaexcel.model.ExcelHeader; 17 | import org.javaexcel.model.ExcelMetaData; 18 | import org.javaexcel.model.ExcelTitle; 19 | import org.javaexcel.model.ExcelType; 20 | import org.javaexcel.util.JsonUtil; 21 | import org.junit.Before; 22 | import org.junit.Test; 23 | 24 | /* 25 | * 报表数据导出(需要合并单元格) 26 | * File name : XmlToExcelWriterTest.java 27 | * @Copyright : luoyoub@163.com 28 | * Description : javaexcel 29 | * Author : Robert 30 | * CreateTime : 2016年4月2日 31 | */ 32 | public class XmlToExcelWriterTest { 33 | private static final int ROWS = 10; 34 | private ExcelMetaData metadata; 35 | private List datas; 36 | 37 | @Test 38 | public void test() { 39 | long begTime = System.currentTimeMillis(); 40 | try { 41 | ExcelWriter writer = ExcelWriterFactory.getWriter(ExcelType.XLSX); 42 | writer.process(metadata, datas, "/Users/Robert/Desktop/QA_test/expense.xlsx"); 43 | } catch (Exception e) { 44 | e.printStackTrace(); 45 | } 46 | 47 | System.out.println("Total:" + (System.currentTimeMillis() - begTime) + "ms"); 48 | } 49 | 50 | /** 51 | * @throws java.lang.Exception 52 | */ 53 | @Before 54 | public void setUp() throws Exception { 55 | metadata = new ExcelMetaData(); 56 | metadata.setFileName("expense"); 57 | metadata.setSheetName("expense"); 58 | 59 | // 设置大表头 60 | this.metadata.setHasHeader(true); 61 | ExcelHeader header = new ExcelHeader(); 62 | header.setHeaderName("报销单"); 63 | header.setRowHeight(40); 64 | ExcelCellStyle hs = new ExcelCellStyle(); 65 | hs.setAlign(CellStyle.ALIGN_CENTER); 66 | hs.setVerticalAlign(CellStyle.ALIGN_CENTER); 67 | hs.setSize((short) 42); 68 | hs.setColor(ExcelColor.RED); 69 | hs.setBackgroundColor(ExcelColor.YELLOW); 70 | header.setCellStyle(hs); 71 | this.metadata.setHeader(header); 72 | 73 | // 设置标题格式 74 | ExcelCellStyle titleStyle = new ExcelCellStyle(); 75 | titleStyle.setAlign(CellStyle.ALIGN_CENTER); 76 | titleStyle.setSize((short) 12); 77 | titleStyle.setItalic(true); 78 | titleStyle.setBackgroundColor(ExcelColor.GREY_25_PERCENT); 79 | this.metadata.setTitleStyle(titleStyle); 80 | 81 | this.metadata.setHasFooter(true); 82 | ExcelFooter footer = new ExcelFooter(); 83 | footer.setRemarks("说明:本文档版权所有,违法必究"); 84 | ExcelCellStyle footcs = new ExcelCellStyle(); 85 | footcs.setVerticalAlign(XSSFCellStyle.VERTICAL_CENTER); 86 | footcs.setColor(ExcelColor.BLUE); 87 | footcs.setItalic(true); 88 | footer.setCellStyle(footcs); 89 | this.metadata.setFooter(footer); 90 | 91 | structureMetaData(); 92 | constructdata(); 93 | } 94 | 95 | private void structureMetaData() { 96 | int rownum = 0; 97 | 98 | // 设置表头 99 | List titles = new ArrayList(); 100 | ExcelTitle t1 = new ExcelTitle(); 101 | t1.setIndex(rownum++); 102 | t1.setName("billType"); 103 | t1.setDisplayName("单据类型"); 104 | t1.setDataType(CellType.TEXT); 105 | t1.setMerge(true); 106 | t1.setColumnWidth(12); 107 | titles.add(t1); 108 | 109 | ExcelTitle t2 = new ExcelTitle(); 110 | t2.setIndex(rownum++); 111 | t2.setName("billName"); 112 | t2.setDisplayName("单据名称"); 113 | t2.setDataType(CellType.TEXT); 114 | t2.setMerge(true); 115 | t2.setColumnWidth(13); 116 | titles.add(t2); 117 | 118 | ExcelTitle t3 = new ExcelTitle(); 119 | t3.setIndex(rownum++); 120 | t3.setName("createUserId"); 121 | t3.setDisplayName("提交人"); 122 | t3.setDataType(CellType.TEXT); 123 | t3.setMerge(true); 124 | titles.add(t3); 125 | 126 | ExcelTitle t4 = new ExcelTitle(); 127 | t4.setIndex(3); 128 | t4.setName("owner"); 129 | t4.setDisplayName("费用归属"); 130 | t4.setDataType(CellType.TEXT); 131 | t4.setMerge(true); 132 | titles.add(t4); 133 | 134 | ExcelTitle t5 = new ExcelTitle(); 135 | t5.setIndex(4); 136 | t5.setName("submitDate"); 137 | t5.setDisplayName("审批提交日期"); 138 | t5.setDataType(CellType.DATE); 139 | t5.setMerge(true); 140 | t5.setColumnWidth(20); 141 | titles.add(t5); 142 | 143 | ExcelTitle t6 = new ExcelTitle(); 144 | t6.setIndex(5); 145 | t6.setName("status"); 146 | t6.setDisplayName("审批状态"); 147 | t6.setDataType(CellType.TEXT); 148 | t6.setMerge(true); 149 | t6.setColumnWidth(12); 150 | titles.add(t6); 151 | 152 | ExcelTitle t7 = new ExcelTitle(); 153 | t7.setName("costDetail"); 154 | t7.setDisplayName("费用详情"); 155 | t7.setDataType(CellType.LIST); 156 | titles.add(t7); 157 | 158 | List subTitles = new ArrayList(); 159 | // 初始化子项 160 | ExcelTitle t8 = new ExcelTitle(); 161 | t8.setIndex(6); 162 | t8.setName("costtype"); 163 | t8.setDisplayName("费用类型"); 164 | t8.setDataType(CellType.TEXT); 165 | subTitles.add(t8); 166 | 167 | ExcelTitle t9 = new ExcelTitle(); 168 | t9.setIndex(7); 169 | t9.setName("costCreateTime"); 170 | t9.setDisplayName("费用发生时间"); 171 | t9.setDataType(CellType.DATE); 172 | subTitles.add(t9); 173 | 174 | ExcelTitle t10 = new ExcelTitle(); 175 | t10.setIndex(8); 176 | t10.setName("costDesc"); 177 | t10.setDisplayName("费用描述"); 178 | t10.setDataType(CellType.TEXT); 179 | subTitles.add(t10); 180 | 181 | ExcelTitle t11 = new ExcelTitle(); 182 | t11.setIndex(9); 183 | t11.setName("costMoney"); 184 | t11.setDisplayName("费用金额"); 185 | t11.setDataType(CellType.MONEY); 186 | subTitles.add(t11); 187 | 188 | t7.setSubTitles(subTitles); 189 | 190 | ExcelTitle t12 = new ExcelTitle(); 191 | t12.setIndex(10); 192 | t12.setName("expenseMoney"); 193 | t12.setDisplayName("报销金额"); 194 | t12.setDataType(CellType.MONEY); 195 | t12.setMerge(true); 196 | titles.add(t12); 197 | 198 | ExcelTitle t13 = new ExcelTitle(); 199 | t13.setIndex(11); 200 | t13.setName("loanMoney"); 201 | t13.setDisplayName("借款金额"); 202 | t13.setDataType(CellType.MONEY); 203 | t13.setMerge(true); 204 | ExcelCellStyle s13 = new ExcelCellStyle(); 205 | s13.setAlign(CellStyle.ALIGN_RIGHT); 206 | t13.setCellStyle(s13); 207 | titles.add(t13); 208 | 209 | this.metadata.setExcelTitle(titles); 210 | } 211 | 212 | @SuppressWarnings("unchecked") 213 | private void constructdata() { 214 | datas = new ArrayList(); 215 | for (int i = 1; i <= ROWS; i++) { 216 | Expense e = new Expense("报销单" + i, "采购费用" + i, "Tim", "产品部", new Date(), "审批中", 880000 + i, 3200 + i); 217 | List detail = new ArrayList(); 218 | CostDetail c1 = new CostDetail("酒店", new Date(), "培训酒店住宿", 3000 + i); 219 | detail.add(c1); 220 | CostDetail c2 = new CostDetail("酒店", new Date(), "培训酒店住宿", 32000 + i); 221 | detail.add(c2); 222 | CostDetail c3 = new CostDetail("酒店", new Date(), "培训酒店住宿", 35000 + i); 223 | detail.add(c3); 224 | CostDetail c4 = new CostDetail("酒店", new Date(), "培训酒店住宿", 8000 + i); 225 | detail.add(c4); 226 | CostDetail c5 = new CostDetail("餐费", new Date(), "培训午餐费", 800 + i); 227 | detail.add(c5); 228 | e.setCostDetail(detail); 229 | String es = JsonUtil.beanToString(e); 230 | Map em = JsonUtil.stringToBean(es, Map.class); 231 | datas.add(em); 232 | } 233 | } 234 | 235 | class Expense { 236 | private String billType; 237 | private String billName; 238 | private String createUserId; 239 | private String owner; 240 | private Date submitDate; 241 | private String status; 242 | private List costDetail; 243 | private double expenseMoney; 244 | private double loanMoney; 245 | 246 | public Expense(String billType, String billName, String createUserId, String owner, Date submitDate, String status, double expenseMoney, double loanMoney) { 247 | this.billType = billType; 248 | this.billName = billName; 249 | this.createUserId = createUserId; 250 | this.owner = owner; 251 | this.submitDate = submitDate; 252 | this.status = status; 253 | this.expenseMoney = expenseMoney; 254 | this.loanMoney = loanMoney; 255 | } 256 | 257 | public List getCostDetail() { 258 | return costDetail; 259 | } 260 | 261 | public void setCostDetail(List costDetail) { 262 | this.costDetail = costDetail; 263 | } 264 | 265 | public String getBillType() { 266 | return billType; 267 | } 268 | 269 | public void setBillType(String billType) { 270 | this.billType = billType; 271 | } 272 | 273 | public String getBillName() { 274 | return billName; 275 | } 276 | 277 | public void setBillName(String billName) { 278 | this.billName = billName; 279 | } 280 | 281 | public String getCreateUserId() { 282 | return createUserId; 283 | } 284 | 285 | public void setCreateUserId(String createUserId) { 286 | this.createUserId = createUserId; 287 | } 288 | 289 | public String getOwner() { 290 | return owner; 291 | } 292 | 293 | public void setOwner(String owner) { 294 | this.owner = owner; 295 | } 296 | 297 | public Date getSubmitDate() { 298 | return submitDate; 299 | } 300 | 301 | public void setSubmitDate(Date submitDate) { 302 | this.submitDate = submitDate; 303 | } 304 | 305 | public String getStatus() { 306 | return status; 307 | } 308 | 309 | public void setStatus(String status) { 310 | this.status = status; 311 | } 312 | 313 | public double getExpenseMoney() { 314 | return expenseMoney; 315 | } 316 | 317 | public void setExpenseMoney(double expenseMoney) { 318 | this.expenseMoney = expenseMoney; 319 | } 320 | 321 | public double getLoanMoney() { 322 | return loanMoney; 323 | } 324 | 325 | public void setLoanMoney(double loanMoney) { 326 | this.loanMoney = loanMoney; 327 | } 328 | } 329 | 330 | class CostDetail { 331 | private String costtype; 332 | private Date costCreateTime; 333 | private String costDesc; 334 | private double costMoney; 335 | 336 | public CostDetail(String costtype, Date costCreateTime, String costDesc, double costMoney) { 337 | this.costtype = costtype; 338 | this.costCreateTime = costCreateTime; 339 | this.costDesc = costDesc; 340 | this.costMoney = costMoney; 341 | } 342 | 343 | public String getCosttype() { 344 | return costtype; 345 | } 346 | 347 | public void setCosttype(String costtype) { 348 | this.costtype = costtype; 349 | } 350 | 351 | public Date getCostCreateTime() { 352 | return costCreateTime; 353 | } 354 | 355 | public void setCostCreateTime(Date costCreateTime) { 356 | this.costCreateTime = costCreateTime; 357 | } 358 | 359 | public String getCostDesc() { 360 | return costDesc; 361 | } 362 | 363 | public void setCostDesc(String costDesc) { 364 | this.costDesc = costDesc; 365 | } 366 | 367 | public double getCostMoney() { 368 | return costMoney; 369 | } 370 | 371 | public void setCostMoney(double costMoney) { 372 | this.costMoney = costMoney; 373 | } 374 | } 375 | } -------------------------------------------------------------------------------- /src/main/java/org/javaexcel/xlsx/XmlToExcelWriter.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.xlsx; 2 | 3 | import java.io.FileOutputStream; 4 | import java.io.FileWriter; 5 | import java.io.IOException; 6 | import java.io.OutputStream; 7 | import java.io.Writer; 8 | import java.nio.file.Files; 9 | import java.nio.file.Paths; 10 | import java.text.ParseException; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | import org.apache.poi.ss.usermodel.CellStyle; 16 | import org.apache.poi.xssf.usermodel.XSSFSheet; 17 | import org.apache.poi.xssf.usermodel.XSSFWorkbook; 18 | import org.javaexcel.ExcelWriter; 19 | import org.javaexcel.model.CellMerge; 20 | import org.javaexcel.model.ExcelMetaData; 21 | import org.javaexcel.model.ExcelTitle; 22 | import org.javaexcel.util.Const; 23 | import org.javaexcel.util.FileUtils; 24 | import org.javaexcel.util.JsonUtil; 25 | import org.javaexcel.util.UUIDUtil; 26 | 27 | /* 28 | * XLSX文件导出工具类(不支持xls) 29 | * 先将数据写入临时XML,然后再将XML压缩进EXCEL文件 30 | * File name : XmlToExcelWriter.java 31 | * Description : excelservice-service 32 | * Author : Robert 33 | * CreateTime : 2016年4月1日 34 | */ 35 | public class XmlToExcelWriter extends ExcelWriter { 36 | // 存储所有合并单元格 37 | private List cellMerges = new ArrayList(); 38 | private SpreadSheetWriter sw; 39 | private CellMerge cellMerge; 40 | 41 | /** 42 | * 导出文件 43 | * 44 | * @throws Exception 45 | */ 46 | public boolean process(ExcelMetaData metedata, List datas, String fileName) throws Exception { 47 | this.metedata = metedata; 48 | this.allDatas.addAll(datas); 49 | boolean result = false; 50 | 51 | String tempFile = Files.createTempFile(UUIDUtil.getUUID(), Const.EXCEL_SUFFIX_XLSX).toString(); 52 | String tmpXml = Files.createTempFile(metedata.getSheetName(), Const.XML_SUFFIX).toString(); 53 | if (fileName.endsWith(Const.EXCEL_SUFFIX_XLS)) { 54 | throw new Exception("Export 2003 version excel is not supported."); 55 | } 56 | 57 | // 校验fileName的父目录是否存在 58 | if (FileUtils.isExistsOfParentDir(fileName)) { 59 | throw new Exception("Output directory does not exist."); 60 | } 61 | 62 | try (OutputStream os = new FileOutputStream(fileName)) { 63 | // 建立工作簿和电子表格对象 64 | wb = new XSSFWorkbook(); 65 | sheet = (XSSFSheet) wb.createSheet(metedata.getSheetName()); 66 | // 持有电子表格数据的xml文件名 例如 /xl/worksheets/sheet1.xml 67 | String sheetRef = ((XSSFSheet) sheet).getPackagePart().getPartName().getName(); 68 | init(); 69 | initStyle(); 70 | 71 | OutputStream out = new FileOutputStream(tempFile); 72 | wb.write(out); 73 | wb.close(); 74 | out.close(); 75 | 76 | // 生成xml文件 77 | Writer wr = new FileWriter(tmpXml); 78 | sw = new SpreadSheetWriter(wr); 79 | generate(); 80 | wr.close(); 81 | 82 | FileUtils.substitute(tempFile, tmpXml, sheetRef.substring(1), os); 83 | result = true; 84 | } catch (Exception e) { 85 | throw e; 86 | } finally { 87 | Files.delete(Paths.get(tempFile)); 88 | Files.delete(Paths.get(tmpXml)); 89 | } 90 | 91 | return result; 92 | } 93 | 94 | /** 95 | * @throws Exception 96 | * 97 | */ 98 | private void generate() throws Exception { 99 | // 电子表格开始 100 | sw.beginSheet(); 101 | 102 | // 设置列宽 103 | sw.beginSetColWidth(); 104 | for (ExcelTitle exct : this.allTitles) { 105 | if (exct.getColumnWidth() > 0) { 106 | sw.setColWidthBeforeSheet(exct.getIndex(), exct.getColumnWidth()); 107 | continue; 108 | } 109 | sw.setColWidthBeforeSheet(exct.getIndex(), exct.getDisplayName().length() * 3.2); 110 | } 111 | sw.endSetColWidth(); 112 | 113 | sw.beginSheetData(); 114 | // 写大表头 115 | writeHeader(); 116 | 117 | // 写标题 118 | writeTitle(); 119 | 120 | // 写数据 121 | writeData(); 122 | 123 | // 写备注 124 | writeFooter(); 125 | sw.endSheetData(); 126 | 127 | // 设置合并单元格 128 | if (!cellMerges.isEmpty()) { 129 | sw.beginMergerCell(cellMerges.size()); 130 | for (CellMerge mc : cellMerges) { 131 | sw.setMergeCell(mc.getBeginColumn(), mc.getBeginCell(), mc.getEndColumn(), mc.getEndCell()); 132 | } 133 | sw.endMergerCell(); 134 | } 135 | 136 | // 电子表格结束 137 | sw.endSheet(); 138 | } 139 | 140 | /** 141 | * @throws IOException 142 | * 143 | */ 144 | private void writeFooter() throws IOException { 145 | if (this.metedata.isHasFooter() && null != this.metedata.getFooter()) { 146 | cellStyle = this.getStyle("footerStyle"); 147 | sw.insertRowWithHeight(rownum, columnSize, this.metedata.getFooter().getRowHeight()); 148 | for (int i = 0; i < this.columnSize; i++) { 149 | if (0 == i) { 150 | sw.createCell(i, metedata.getFooter().getRemarks(), cellStyle.getIndex()); 151 | cellMerge = new CellMerge(rownum, i, rownum, columnSize - 1); 152 | cellMerges.add(cellMerge); 153 | continue; 154 | } 155 | sw.createCell(i, cellStyle.getIndex()); 156 | } 157 | sw.endRow(); 158 | } 159 | } 160 | 161 | /** 162 | * @throws IOException 163 | * 164 | */ 165 | private void writeHeader() throws IOException { 166 | if (this.metedata.isHasHeader() && null != this.metedata.getHeader()) { 167 | cellStyle = this.getStyle("headerStyle"); 168 | sw.insertRowWithHeight(rownum, columnSize, metedata.getHeader().getRowHeight()); 169 | for (int i = 0; i < columnSize; i++) { 170 | if (0 == i) { 171 | sw.createCell(i, metedata.getHeader().getHeaderName(), cellStyle.getIndex()); 172 | cellMerge = new CellMerge(rownum, i, rownum, columnSize - 1); 173 | cellMerges.add(cellMerge); 174 | continue; 175 | } 176 | sw.createCell(i, cellStyle.getIndex()); 177 | } 178 | 179 | sw.endRow(); 180 | rownum++; 181 | } 182 | } 183 | 184 | /** 185 | * @throws IOException 186 | * @throws ParseException 187 | * 188 | */ 189 | @SuppressWarnings("unchecked") 190 | private void writeData() throws IOException, ParseException { 191 | for (Object object : allDatas) { 192 | Map dataMap = JsonUtil.stringToBean(JsonUtil.beanToString(object), Map.class); 193 | if (null == dataMap || dataMap.isEmpty()) { 194 | continue; 195 | } 196 | 197 | int rowsize = getColumns(dataMap); 198 | int maxRow = rownum + rowsize - 1; 199 | if (rowsize > 0) { 200 | for (int i = 0; i < rowsize; i++) { 201 | sw.insertRowWithHeight(rownum, columnSize, DEFAULTROWHEIGHT); 202 | for (ExcelTitle eh : this.metedata.getExcelTitle()) { 203 | Object obj = dataMap.get(eh.getName()); 204 | cellStyle = this.getStyle("cellstyle_" + eh.getIndex()); 205 | if (eh.isMerge()) { 206 | if (0 == i) { 207 | cellMerge = new CellMerge(rownum, eh.getIndex(), maxRow, eh.getIndex()); 208 | cellMerges.add(cellMerge); 209 | createCell(eh, obj, cellStyle); 210 | continue; 211 | } 212 | sw.createCell(eh.getIndex(), cellStyle.getIndex()); 213 | } else if (!eh.getSubTitles().isEmpty() && (obj instanceof List)) { 214 | List list = (List) obj; 215 | Map detailData = (Map) list.get(i); 216 | for (ExcelTitle ele : eh.getSubTitles()) { 217 | cellStyle = this.getStyle("cellstyle_" + ele.getIndex()); 218 | createCell(ele, detailData.get(ele.getName()), cellStyle); 219 | } 220 | } 221 | } 222 | rownum++; 223 | sw.endRow(); 224 | } 225 | } else { 226 | writeToRow(dataMap); 227 | } 228 | } 229 | } 230 | 231 | private void createCell(ExcelTitle ete, Object obj, CellStyle style) throws IOException, ParseException { 232 | String result = ""; 233 | if (JsonUtil.isEmpty(obj)) { 234 | if (!JsonUtil.isEmpty(ete.getFillChar())) { 235 | result = ete.getFillChar(); 236 | } 237 | sw.createCell(ete.getIndex(), result, style.getIndex()); 238 | return; 239 | } 240 | result = obj.toString(); 241 | sw.createCell(ete.getIndex(), result, style.getIndex()); 242 | } 243 | 244 | private void writeToRow(Map dataMap) throws IOException, ParseException { 245 | sw.insertRowWithHeight(rownum++, columnSize, DEFAULTROWHEIGHT); 246 | for (ExcelTitle eh : this.allTitles) { 247 | cellStyle = this.getStyle("cellstyle_" + eh.getIndex()); 248 | createCell(eh, dataMap.get(eh.getName()), cellStyle); 249 | } 250 | sw.endRow(); 251 | } 252 | 253 | @SuppressWarnings("rawtypes") 254 | private static int getColumns(Map dataMap) { 255 | for (Object obj : dataMap.values()) { 256 | if (obj instanceof List) { 257 | return ((List) obj).size(); 258 | } 259 | } 260 | return 0; 261 | } 262 | 263 | private void writeTitle() throws IOException { 264 | if (null == metedata.getExcelTitle() || metedata.getExcelTitle().isEmpty()) { 265 | return; 266 | } 267 | 268 | cellStyle = this.getStyle("titleStyle"); 269 | if (metedata.isHasSubTitle() && null != this.metedata.getExcelTitle() && !this.metedata.getExcelTitle().isEmpty()) { 270 | // 写EXCEL表头 271 | for (int i = 0; i < 2; i++) { 272 | sw.insertRowWithHeight(rownum, columnSize, DEFAULTROWHEIGHT); 273 | for (ExcelTitle excelTitle : metedata.getExcelTitle()) { 274 | if (excelTitle.isMerge()) { 275 | if (0 == i) { 276 | cellMerge = new CellMerge(rownum, excelTitle.getIndex(), rownum + 1, excelTitle.getIndex()); 277 | cellMerges.add(cellMerge); 278 | sw.createCell(excelTitle.getIndex(), excelTitle.getDisplayName(), cellStyle.getIndex()); 279 | continue; 280 | } 281 | sw.createCell(excelTitle.getIndex(), cellStyle.getIndex()); 282 | } else if (null != excelTitle.getSubTitles() && !excelTitle.getSubTitles().isEmpty()) { 283 | for (int j = 0; j < excelTitle.getSubTitles().size(); j++) { 284 | ExcelTitle ct = excelTitle.getSubTitles().get(j); 285 | if (0 == i) { 286 | if (0 == j) { 287 | cellMerge = new CellMerge(rownum, ct.getIndex(), rownum, 288 | excelTitle.getSubTitles().get(excelTitle.getSubTitles().size() - 1).getIndex()); 289 | cellMerges.add(cellMerge); 290 | sw.createCell(ct.getIndex(), ct.getDisplayName(), cellStyle.getIndex()); 291 | continue; 292 | } 293 | sw.createCell(ct.getIndex(), cellStyle.getIndex()); 294 | } else { 295 | sw.createCell(ct.getIndex(), ct.getDisplayName(), cellStyle.getIndex()); 296 | } 297 | } 298 | } 299 | } 300 | sw.endRow(); 301 | rownum++; 302 | } 303 | } else { 304 | sw.insertRowWithHeight(rownum++, columnSize, DEFAULTROWHEIGHT); 305 | for (ExcelTitle et : this.allTitles) { 306 | sw.createCell(et.getIndex(), et.getDisplayName(), cellStyle.getIndex()); 307 | } 308 | sw.endRow(); 309 | } 310 | } 311 | } -------------------------------------------------------------------------------- /src/test/java/org/javaexcel/xlsx/ComplexExcelExportTest.java: -------------------------------------------------------------------------------- 1 | package org.javaexcel.xlsx; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import org.apache.poi.ss.usermodel.CellStyle; 9 | import org.apache.poi.xssf.usermodel.XSSFCellStyle; 10 | import org.javaexcel.ExcelWriter; 11 | import org.javaexcel.ExcelWriterFactory; 12 | import org.javaexcel.model.CellType; 13 | import org.javaexcel.model.ExcelCellStyle; 14 | import org.javaexcel.model.ExcelColor; 15 | import org.javaexcel.model.ExcelFooter; 16 | import org.javaexcel.model.ExcelHeader; 17 | import org.javaexcel.model.ExcelMetaData; 18 | import org.javaexcel.model.ExcelTitle; 19 | import org.javaexcel.model.ExcelType; 20 | import org.javaexcel.util.JsonUtil; 21 | import org.junit.Before; 22 | import org.junit.Test; 23 | 24 | /* 25 | * File name : ComplexExcelExport.java 26 | * @Copyright : luoyoub@163.com 27 | * Description : excelservice-service 28 | * Author : Robert 29 | * CreateTime : 2016年3月28日 30 | */ 31 | public class ComplexExcelExportTest { 32 | private static final int ROWS = 6; 33 | private ExcelMetaData metadata; 34 | private List datas; 35 | 36 | @Test 37 | public void test_XLS() { 38 | try { 39 | long begTime = System.currentTimeMillis(); 40 | ExcelWriter writer = ExcelWriterFactory.getWriter(ExcelType.XLSX); 41 | writer.process(this.metadata, this.datas, 42 | "/Users/Robert/Desktop/QA_test/expense_test.xlsx"); 43 | System.out.println("XLS Total:" + (System.currentTimeMillis() - begTime) + "ms"); 44 | } catch (Exception e) { 45 | e.printStackTrace(); 46 | } 47 | } 48 | 49 | /** 50 | * @throws java.lang.Exception 51 | */ 52 | @Before 53 | public void setUp() throws Exception { 54 | metadata = new ExcelMetaData(); 55 | metadata.setFileName("test"); 56 | metadata.setSheetName("test data"); 57 | metadata.setHasSubTitle(true); 58 | 59 | // 设置大表头 60 | this.metadata.setHasHeader(true); 61 | ExcelHeader header = new ExcelHeader(); 62 | header.setHeaderName("报销单"); 63 | header.setRowHeight(50); 64 | ExcelCellStyle hs = new ExcelCellStyle(); 65 | hs.setAlign(CellStyle.ALIGN_CENTER); 66 | hs.setVerticalAlign(CellStyle.ALIGN_CENTER); 67 | hs.setSize((short) 42); 68 | hs.setColor(ExcelColor.RED); 69 | header.setCellStyle(hs); 70 | this.metadata.setHeader(header); 71 | 72 | // 设置标题格式 73 | ExcelCellStyle titleStyle = new ExcelCellStyle(); 74 | titleStyle.setAlign(CellStyle.ALIGN_CENTER); 75 | titleStyle.setSize((short) 12); 76 | titleStyle.setItalic(true); 77 | titleStyle.setBackgroundColor(ExcelColor.GREY_25_PERCENT); 78 | this.metadata.setTitleStyle(titleStyle); 79 | 80 | this.metadata.setHasFooter(true); 81 | ExcelFooter footer = new ExcelFooter(); 82 | footer.setRemarks("说明:本文档版权所有,违法必究"); 83 | ExcelCellStyle footcs = new ExcelCellStyle(); 84 | footcs.setVerticalAlign(XSSFCellStyle.VERTICAL_CENTER); 85 | footcs.setColor(ExcelColor.BLUE); 86 | footcs.setItalic(true); 87 | footer.setCellStyle(footcs); 88 | this.metadata.setFooter(footer); 89 | 90 | // long btime = System.currentTimeMillis(); 91 | structureMetaData(); 92 | constructdata(); 93 | // System.out.println("init data:" + (System.currentTimeMillis() - 94 | // btime) + "ms"); 95 | // System.out.println(JsonUtil.beanToString(req)); 96 | } 97 | 98 | private void structureMetaData() { 99 | int rownum = 0; 100 | 101 | // 设置表头 102 | List titles = new ArrayList(); 103 | ExcelTitle t1 = new ExcelTitle(); 104 | t1.setIndex(rownum++); 105 | t1.setName("billType"); 106 | t1.setDisplayName("单据类型"); 107 | t1.setDataType(CellType.TEXT); 108 | t1.setMerge(true); 109 | t1.setColumnWidth(12); 110 | titles.add(t1); 111 | 112 | ExcelTitle t2 = new ExcelTitle(); 113 | t2.setIndex(rownum++); 114 | t2.setName("billName"); 115 | t2.setDisplayName("单据名称"); 116 | t2.setDataType(CellType.TEXT); 117 | t2.setMerge(true); 118 | t2.setColumnWidth(13); 119 | titles.add(t2); 120 | 121 | ExcelTitle t3 = new ExcelTitle(); 122 | t3.setIndex(rownum++); 123 | t3.setName("createUserId"); 124 | t3.setDisplayName("提交人"); 125 | t3.setDataType(CellType.TEXT); 126 | t3.setMerge(true); 127 | titles.add(t3); 128 | 129 | ExcelTitle t4 = new ExcelTitle(); 130 | t4.setIndex(3); 131 | t4.setName("owner"); 132 | t4.setDisplayName("费用归属"); 133 | t4.setDataType(CellType.TEXT); 134 | t4.setMerge(true); 135 | titles.add(t4); 136 | 137 | ExcelTitle t5 = new ExcelTitle(); 138 | t5.setIndex(4); 139 | t5.setName("submitDate"); 140 | t5.setDisplayName("审批提交日期"); 141 | t5.setDataType(CellType.DATE); 142 | t5.setMerge(true); 143 | t5.setColumnWidth(20); 144 | titles.add(t5); 145 | 146 | ExcelTitle t6 = new ExcelTitle(); 147 | t6.setIndex(5); 148 | t6.setName("status"); 149 | t6.setDisplayName("审批状态"); 150 | t6.setDataType(CellType.TEXT); 151 | t6.setMerge(true); 152 | titles.add(t6); 153 | 154 | ExcelTitle t7 = new ExcelTitle(); 155 | t7.setName("costDetail"); 156 | t7.setDisplayName("费用详情"); 157 | t7.setDataType(CellType.LIST); 158 | titles.add(t7); 159 | 160 | List subTitles = new ArrayList(); 161 | // 初始化子项 162 | ExcelTitle t8 = new ExcelTitle(); 163 | t8.setIndex(6); 164 | t8.setName("costtype"); 165 | t8.setDisplayName("费用类型"); 166 | t8.setDataType(CellType.TEXT); 167 | subTitles.add(t8); 168 | 169 | ExcelTitle t9 = new ExcelTitle(); 170 | t9.setIndex(7); 171 | t9.setName("costCreateTime"); 172 | t9.setDisplayName("费用发生时间"); 173 | t9.setDataType(CellType.DATE); 174 | subTitles.add(t9); 175 | 176 | ExcelTitle t10 = new ExcelTitle(); 177 | t10.setIndex(8); 178 | t10.setName("costDesc"); 179 | t10.setDisplayName("费用描述"); 180 | t10.setDataType(CellType.TEXT); 181 | subTitles.add(t10); 182 | 183 | ExcelTitle t11 = new ExcelTitle(); 184 | t11.setIndex(9); 185 | t11.setName("costMoney"); 186 | t11.setDisplayName("费用金额"); 187 | t11.setDataType(CellType.MONEY); 188 | subTitles.add(t11); 189 | 190 | t7.setSubTitles(subTitles); 191 | 192 | ExcelTitle t12 = new ExcelTitle(); 193 | t12.setIndex(10); 194 | t12.setName("expenseMoney"); 195 | t12.setDisplayName("报销金额"); 196 | t12.setDataType(CellType.MONEY); 197 | t12.setMerge(true); 198 | titles.add(t12); 199 | 200 | ExcelTitle t13 = new ExcelTitle(); 201 | t13.setIndex(11); 202 | t13.setName("loanMoney"); 203 | t13.setDisplayName("借款金额"); 204 | t13.setDataType(CellType.MONEY); 205 | t13.setMerge(true); 206 | titles.add(t13); 207 | 208 | this.metadata.setExcelTitle(titles); 209 | } 210 | 211 | /** 212 | * 213 | */ 214 | @SuppressWarnings("unchecked") 215 | private void constructdata() { 216 | this.datas = new ArrayList(); 217 | for (int i = 1; i <= ROWS; i++) { 218 | Expense e = new Expense("报销单" + i, "采购费用" + i, "Tim", "产品部", new Date(), "审批中", 880000 + i, 3200 + i); 219 | List detail = new ArrayList(); 220 | CostDetail c1 = new CostDetail("酒店", new Date(), "培训酒店住宿", 3000 + i); 221 | detail.add(c1); 222 | CostDetail c2 = new CostDetail("酒店", new Date(), "培训酒店住宿", 32000 + i); 223 | detail.add(c2); 224 | CostDetail c3 = new CostDetail("酒店", new Date(), "培训酒店住宿", 35000 + i); 225 | detail.add(c3); 226 | CostDetail c4 = new CostDetail("酒店", new Date(), "培训酒店住宿", 8000 + i); 227 | detail.add(c4); 228 | CostDetail c5 = new CostDetail("餐费", new Date(), "培训午餐费", 800 + i); 229 | detail.add(c5); 230 | e.setCostDetail(detail); 231 | String es = JsonUtil.beanToString(e); 232 | Map em = JsonUtil.stringToBean(es, Map.class); 233 | datas.add(em); 234 | } 235 | } 236 | 237 | class Expense { 238 | private String billType; 239 | private String billName; 240 | private String createUserId; 241 | private String owner; 242 | private Date submitDate; 243 | private String status; 244 | private List costDetail; 245 | private double expenseMoney; 246 | private double loanMoney; 247 | 248 | public Expense(String billType, String billName, String createUserId, String owner, Date submitDate, String status, double expenseMoney, double loanMoney) { 249 | this.billType = billType; 250 | this.billName = billName; 251 | this.createUserId = createUserId; 252 | this.owner = owner; 253 | this.submitDate = submitDate; 254 | this.status = status; 255 | this.expenseMoney = expenseMoney; 256 | this.loanMoney = loanMoney; 257 | } 258 | 259 | public List getCostDetail() { 260 | return costDetail; 261 | } 262 | 263 | public void setCostDetail(List costDetail) { 264 | this.costDetail = costDetail; 265 | } 266 | 267 | public String getBillType() { 268 | return billType; 269 | } 270 | 271 | public void setBillType(String billType) { 272 | this.billType = billType; 273 | } 274 | 275 | public String getBillName() { 276 | return billName; 277 | } 278 | 279 | public void setBillName(String billName) { 280 | this.billName = billName; 281 | } 282 | 283 | public String getCreateUserId() { 284 | return createUserId; 285 | } 286 | 287 | public void setCreateUserId(String createUserId) { 288 | this.createUserId = createUserId; 289 | } 290 | 291 | public String getOwner() { 292 | return owner; 293 | } 294 | 295 | public void setOwner(String owner) { 296 | this.owner = owner; 297 | } 298 | 299 | public Date getSubmitDate() { 300 | return submitDate; 301 | } 302 | 303 | public void setSubmitDate(Date submitDate) { 304 | this.submitDate = submitDate; 305 | } 306 | 307 | public String getStatus() { 308 | return status; 309 | } 310 | 311 | public void setStatus(String status) { 312 | this.status = status; 313 | } 314 | 315 | public double getExpenseMoney() { 316 | return expenseMoney; 317 | } 318 | 319 | public void setExpenseMoney(double expenseMoney) { 320 | this.expenseMoney = expenseMoney; 321 | } 322 | 323 | public double getLoanMoney() { 324 | return loanMoney; 325 | } 326 | 327 | public void setLoanMoney(double loanMoney) { 328 | this.loanMoney = loanMoney; 329 | } 330 | } 331 | 332 | class CostDetail { 333 | private String costtype; 334 | private Date costCreateTime; 335 | private String costDesc; 336 | private double costMoney; 337 | 338 | public CostDetail(String costtype, Date costCreateTime, String costDesc, double costMoney) { 339 | this.costtype = costtype; 340 | this.costCreateTime = costCreateTime; 341 | this.costDesc = costDesc; 342 | this.costMoney = costMoney; 343 | } 344 | 345 | public String getCosttype() { 346 | return costtype; 347 | } 348 | 349 | public void setCosttype(String costtype) { 350 | this.costtype = costtype; 351 | } 352 | 353 | public Date getCostCreateTime() { 354 | return costCreateTime; 355 | } 356 | 357 | public void setCostCreateTime(Date costCreateTime) { 358 | this.costCreateTime = costCreateTime; 359 | } 360 | 361 | public String getCostDesc() { 362 | return costDesc; 363 | } 364 | 365 | public void setCostDesc(String costDesc) { 366 | this.costDesc = costDesc; 367 | } 368 | 369 | public double getCostMoney() { 370 | return costMoney; 371 | } 372 | 373 | public void setCostMoney(double costMoney) { 374 | this.costMoney = costMoney; 375 | } 376 | } 377 | } --------------------------------------------------------------------------------