1 背景
- 需求:
项目需求,导出excel或word;
批量数据导入;
… - 导入导出插件(API):
前端导出(jquery.wordexport.js、tableExport.js、Blob对象、xlsx等)
后端导出(poi、poi-tl、easypoi)
- 具体情况分析:
简单导入导出、复杂(多数据)导入导出、带图片导入导出
2 前端导出
前提:只支持简单导出(内容少,不要求样式,只支持导出)
2.1 jquery.wordexport.js
引入js:
jquery.js
FileSaver.js //处理图片
jquery.wordexport.js
使用
$("#showDIV").wordExport(FileName)
处理
function export() {
var htmlstr = $("#page").html();//table所在div
$('#printWord').html(htmlstr);
$('#printWord div[data-role=pager]').remove();//把分页div删除
$('#showDIV script').remove();//div引用的js代码删除
$('#name').html(name);
$("#showDIV").wordExport(FileName)
}
<div id="showDIV" style="display:none">
<style>
#printWord table {
border: 1px solid #ddd;
border-collapse: collapse;
width: 95%;
margin: auto;
}
#printWord table tr td {
border: 1px solid #ddd;
}
#printWord table tr th {
border: 1px solid #ddd;
border-radius: 10px;
}
</style>
<h2 style="text-align: center;">
隐患等级数量统计
</h2>
<div style="text-align: right;margin-right: 50px; font-size: 16px;font-style: italic">
<span style="color: blue;">标题</span>:<span id="name"></span>
</div>
<div id="printWord" />
</div>
博客:
html:https://www.cnblogs.com/wyl1924/p/9896448.html?ivk_sa=1024320u
vue:https://blog.csdn.net/MISS_CJL/article/details/89466710
2.2 tableExport.js
引入js:
jquery.js
FileSaver.js //处理图片
tableExport.js
base64.js //避免导出中文时乱码的js文件
使用
$("#btnExport").click(function(){
$("table").tableExport({
type: 'excel',
ignoreRow: [1,2],//不导出的行:从0开始
ignoreColumn: [5],//不导出的列:从0开始,忽略第5列
htmlContent: true,
fileName: title,//文件名
worksheetName: title,//sheet表的名字
excelstyles: ['text-align', 'font-size', 'font-weight', 'line-height', 'border-collapse', 'height', 'overflow', 'white-space', 'text-overflow'],若table表格中使用了以下指定的样式属性,则将该样式同步到Excel中(可以保留表格原有的样式到Excel中)
});
});
2.3 前端利用Blob实现文件导出
function daochu() {
// 使用outerHTML属性获取整个table元素的HTML代码(包括<table>标签),然后包装成一个完整的HTML文档,设置charset为urf-8以防止中文乱码
var html = "<html><head><meta charset='utf-8' /></head><body>" + document.getElementById("aaa").outerHTML + "</body></html>";
html = html.replace("display: none", "");
html = html.replace("table table-striped table-bordered table-condensed", "");
// 实例化一个Blob对象,其构造函数的第一个参数是包含文件内容的数组,第二个参数是包含文件类型属性的对象
var blob = new Blob([html], {
type: "application/vnd.ms-excel"
});
var a = document.getElementById("print-click");
//var textName = document.getElementById("biaoti").innerHTML;
var textName = "整改意见";
// 利用URL.createObjectURL()方法为a元素生成blob URL
a.href = URL.createObjectURL(blob);
// 设置文件名,目前只有Chrome和FireFox支持此属性
a.download = textName + ".xls";
a.click();
}
<div style="display: none;">
<a id="print-click">超链接_导出表格</a>
</div>
type有以下选择:
1、“application/msword” Word
2、“application/vnd.ms-excel” Excel
2.4 xlsx插件导出(vue项目)
2.4.1 安装依赖
$ npm install -S file-saver
$ npm install -S xlsx
2.4.2 引入
import FileSaver from "file-saver";
import XLSX from "xlsx";
2.4.3 使用
exportExcel () {
this.getData(() => {
this.$nextTick(() => {
let wb = XLSX.utils.table_to_book(
document.querySelector("#out-table")
);
let wbout = XLSX.write(wb, {
bookType: "xlsx",
bookSST: true,
type: "array",
});
try {
FileSaver.saveAs(
new Blob([wbout], { type: "application/octet-stream" }),
"水质监测报告.xlsx"
);
} catch (e) {
if (typeof console !== "undefined") console.log(e, wbout);
}
return wbout;
});
});
},
2.4 vue-json-excel导出(vue项目)
http://events.jianshu.io/p/f4195f2a23ee
3 后端导出——poi
3.1 依赖
<!-- poi office -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.9</version>
</dependency>
3.2 官方API
https://poi.apache.org/
4 POI操作excel
4.1 POI操作excel常用API
获得文档对象(工作簿):
xls: Workbook workbook= new HSSFWorkbook();
大数据量excel对象:Workbook workbook= new SXSSFWorkbook();
xlsx: Workbook workbook= new XSSFWorkbook();(常用)
Workbook workbook= new XSSFWorkbook(new FileInputStream());
获取工作表对象:
Sheet sheet = workbook.createSheet(“工作表名”);
Sheet sheet = workbook.getSheet(“工作表名”);
Sheet sheet = workbook.getSheetAt(索引);
获取行对象:
Row row = sheet.createRow(索引);
Row row = sheet.getRow(索引);
获取有效行:(如果sheet中一行数据都没有则返回-1,只有第一行有数据则返回0,最后有数据的行是第n行则返回 n-1)
int rowcount = sheet.getLastRowNum();
获取单元格对象:
Cell cell = row.createCell(索引)
Cell cell = row.getCell((short) 索引)
取得一行的有效单元格个数:(如果row中一列数据都没有则返回-1,只有第一列有数据则返回1,最后有数据的列是第n列则返回 n)
row.getLastCellNum();
设置行样式、字体:
CellStyle cellStyle = workbook.createCellStyle();
Font font = workbook.createFont();
cellStyle .setFont(font);
row.setRowStyle(CellStyle);
workbook(文件)=> sheet (表格) => row(行) => cell (单元格)
4.2 POI导出excel——示例工具类
public class ExportExcelUtil {
public static void ExportExcel(List<Person> list, String[] titles) {
SXSSFWorkbook wb = new SXSSFWorkbook();
Sheet sheet = wb.createSheet();
Row row = sheet.createRow(0);
//给单元格设置样式
CellStyle cellStyle = wb.createCellStyle();
Font font = wb.createFont();
//设置字体大小
font.setFontHeightInPoints((short) 12);
//设置字体加粗
font.setBold(true);
//给字体设置样式
cellStyle.setFont(font);
//设置单元格背景颜色
cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
//设置单元格填充样式(使用纯色背景颜色填充)
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
for (int i = 0; i < titles.length; i++) {
Cell cell = row.createCell(i);
cell.setCellValue(titles[i]);
cell.setCellStyle(cellStyle);
//设置列的宽度
sheet.setColumnWidth(i, 200*50);
}
for (int j = 0; j < list.size(); j++) {
Row rowData = sheet.createRow(j + 1);
Person person = list.get(j);
Cell cell = rowData.createCell(0);
cell.setCellValue(person.getId());
}
String fileName = "D:/人员信息导出.xlsx";
try {
FileOutputStream fileOutputStream = new FileOutputStream(fileName);
wb.write(fileOutputStream);
wb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
合并单元格
//合并单元格,参数依次为起始行、结束行、起始列、结束列
CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 5, 0, 5);
sheet.addMergedRegion(cellRangeAddress);
包含图片
File file = new File(url) ;
if (file.exists()){
BufferedImage bufferedImage = ImageIO.read(file) ;
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpg", byteArrayOut);
//画图的顶级管理器,一个sheet只能获取一个(一定要注意这点)
HSSFPatriarch patriarch = sheet1.createDrawingPatriarch();
//anchor主要用于设置图片的属性(端锚)
//HSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, short col1, int row1, short col2, int row2)
//dx1 dy1 起始单元格中的x,y坐标,dx2 dy2 结束单元格中的x,y坐标
//col1,row1 指定起始的单元格,col2,row2 指定结束的单元格
XSSFClientAnchor anchor = new XSSFClientAnchor(10, 10, 990, 250, (short)0, 0, (short) 0, 0);
drawingPatriarch.createPicture(anchor, workbook.addPicture(byteArrayOut.toByteArray(), XSSFWorkbook.PICTURE_TYPE_JPEG));
} else {
cell.setCellType(XSSFCell.CELL_TYPE_STRING);
cell.setCellValue("");
}
4.3 POI导出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.google.common.collect.Lists;
import com.sunny.reverse.common.utils.Encodes;
import com.sunny.reverse.common.utils.Reflections;
import com.sunny.reverse.common.utils.excel.annotation.ExcelField;
import com.sunny.reverse.modules.sys.utils.DictUtils;
/**
* 导出Excel文件(导出“XLSX”格式,支持大数据量导出 @see org.apache.poi.ss.SpreadsheetVersion)
* @author ThinkGem
* @version 2013-04-21
*/
public class ExportExcel {
private static Logger log = LoggerFactory.getLogger(ExportExcel.class);
/**
* 工作薄对象
*/
private SXSSFWorkbook wb;
/**
* 工作表对象
*/
private Sheet sheet;
/**
* 样式列表
*/
private Map<String, CellStyle> styles;
/**
* 当前行号
*/
private int rownum;
/**
* 注解列表(Object[]{ ExcelField, Field/Method })
*/
List<Object[]> annotationList = Lists.newArrayList();
/**
* 构造函数
* @param title 表格标题,传“空值”,表示无标题
* @param cls 实体对象,通过annotation.ExportField获取标题
*/
public ExportExcel(String title, Class<?> cls){
this(title, cls, 1);
}
/**
* 构造函数
* @param title 表格标题,传“空值”,表示无标题
* @param cls 实体对象,通过annotation.ExportField获取标题
* @param type 导出类型(1:导出数据;2:导出模板)
* @param groups 导入分组
*/
public ExportExcel(String title, Class<?> cls, int type, int... groups){
// Get annotation field
Field[] fs = cls.getDeclaredFields();
for (Field f : fs){
ExcelField ef = f.getAnnotation(ExcelField.class);
if (ef != null && (ef.type()==0 || ef.type()==type)){
if (groups!=null && groups.length>0){
boolean inGroup = false;
for (int g : groups){
if (inGroup){
break;
}
for (int efg : ef.groups()){
if (g == efg){
inGroup = true;
annotationList.add(new Object[]{ef, f});
break;
}
}
}
}else{
annotationList.add(new Object[]{ef, f});
}
}
}
// Get annotation method
Method[] ms = cls.getDeclaredMethods();
for (Method m : ms){
ExcelField ef = m.getAnnotation(ExcelField.class);
if (ef != null && (ef.type()==0 || ef.type()==type)){
if (groups!=null && groups.length>0){
boolean inGroup = false;
for (int g : groups){
if (inGroup){
break;
}
for (int efg : ef.groups()){
if (g == efg){
inGroup = true;
annotationList.add(new Object[]{ef, m});
break;
}
}
}
}else{
annotationList.add(new Object[]{ef, m});
}
}
}
// Field sorting
Collections.sort(annotationList, new Comparator<Object[]>() {
public int compare(Object[] o1, Object[] o2) {
return new Integer(((ExcelField)o1[0]).sort()).compareTo(
new Integer(((ExcelField)o2[0]).sort()));
};
});
// Initialize
List<String> headerList = Lists.newArrayList();
for (Object[] os : annotationList){
String t = ((ExcelField)os[0]).title();
// 如果是导出,则去掉注释
if (type==1){
String[] ss = StringUtils.split(t, "**", 2);
if (ss.length==2){
t = ss[0];
}
}
headerList.add(t);
}
initialize(title, headerList);
}
/**
* 构造函数
* @param title 表格标题,传“空值”,表示无标题
* @param headers 表头数组
*/
public ExportExcel(String title, String[] headers) {
initialize(title, Lists.newArrayList(headers));
}
/**
* 构造函数
* @param title 表格标题,传“空值”,表示无标题
* @param headerList 表头列表
*/
public ExportExcel(String title, List<String> headerList) {
initialize(title, headerList);
}
/**
* 初始化函数
* @param title 表格标题,传“空值”,表示无标题
* @param headerList 表头列表
*/
private void initialize(String title, List<String> headerList) {
this.wb = new SXSSFWorkbook(500);
this.sheet = wb.createSheet("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 RuntimeException("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);
}
for (int i = 0; i < headerList.size(); i++) {
int colWidth = sheet.getColumnWidth(i)*2;
sheet.setColumnWidth(i, colWidth < 3000 ? 3000 : colWidth);
}
log.debug("Initialize success.");
}
/**
* 创建表格样式
* @param wb 工作薄对象
* @return 样式列表
*/
private Map<String, CellStyle> createStyles(Workbook wb) {
Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
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, 0, Class.class);
}
/**
* 添加一个单元格
* @param row 添加的行
* @param column 添加列号
* @param val 添加值
* @param align 对齐方式(1:靠左;2:居中;3:靠右)
* @return 单元格对象
*/
public Cell addCell(Row row, int column, Object val, int align, Class<?> fieldType){
Cell cell = row.createCell(column);
String cellFormatString = "@";
try {
if(val == null){
cell.setCellValue("");
}else if(fieldType != Class.class){
cell.setCellValue((String)fieldType.getMethod("setValue", Object.class).invoke(null, val));
}else{
if(val instanceof String) {
cell.setCellValue((String) val);
}else if(val instanceof Integer) {
cell.setCellValue((Integer) val);
cellFormatString = "0";
}else if(val instanceof Long) {
cell.setCellValue((Long) val);
cellFormatString = "0";
}else if(val instanceof Double) {
cell.setCellValue((Double) val);
cellFormatString = "0.00";
}else if(val instanceof Float) {
cell.setCellValue((Float) val);
cellFormatString = "0.00";
}else if(val instanceof Date) {
cell.setCellValue((Date) val);
cellFormatString = "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>=1&&align<=3?align:"")));
style.setDataFormat(wb.createDataFormat().getFormat(cellFormatString));
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 <E> ExportExcel setDataList(List<E> 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.value())){
val = Reflections.invokeGetter(e, ef.value());
}else{
if (os[1] instanceof Field){
val = Reflections.invokeGetter(e, ((Field)os[1]).getName());
}else if (os[1] instanceof Method){
val = Reflections.invokeMethod(e, ((Method)os[1]).getName(), new Class[] {}, new Object[] {});
}
}
// If is dict, get dict label
if (StringUtils.isNotBlank(ef.dictType())){
val = DictUtils.getDictLabel(val==null?"":val.toString(), ef.dictType(), "");
}
}catch(Exception ex) {
// Failure to ignore
log.info(ex.toString());
val = "";
}
this.addCell(row, colunm++, val, ef.align(), ef.fieldType());
sb.append(val + ", ");
}
log.debug("Write success: ["+row.getRowNum()+"] "+sb.toString());
}
return this;
}
/**
* 输出数据流
* @param os 输出数据流
*/
public ExportExcel write(OutputStream os) throws IOException{
wb.write(os);
return this;
}
/**
* 输出到客户端
* @param fileName 输出文件名
*/
public ExportExcel write(HttpServletResponse response, String fileName) throws IOException{
response.reset();
response.setContentType("application/octet-stream; charset=utf-8");
response.setHeader("Content-Disposition", "attachment; filename="+Encodes.urlEncode(fileName));
write(response.getOutputStream());
return this;
}
/**
* 输出到文件
* @param fileName 输出文件名
*/
public ExportExcel writeFile(String name) throws FileNotFoundException, IOException{
FileOutputStream os = new FileOutputStream(name);
this.write(os);
return this;
}
/**
* 清理临时文件
*/
public ExportExcel dispose(){
wb.dispose();
return this;
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelField {
/**
* 导出字段名(默认调用当前字段的“get”方法,如指定导出字段为对象,请填写“对象名.对象属性”,例:“area.name”、“office.name”)
*/
String value() default "";
/**
* 导出字段标题(需要添加批注请用“**”分隔,标题**批注,仅对导出模板有效)
*/
String title();
/**
* 字段类型(0:导出导入;1:仅导出;2:仅导入)
*/
int type() default 0;
/**
* 导出字段对齐方式(0:自动;1:靠左;2:居中;3:靠右)
*/
int align() default 0;
/**
* 导出字段字段排序(升序)
*/
int sort() default 0;
/**
* 如果是字典类型,请设置字典的type值
*/
String dictType() default "";
/**
* 反射类型
*/
Class<?> fieldType() default Class.class;
/**
* 字段归属组(根据分组导出导入)
*/
int[] groups() default {};
}
使用
@ExcelField(title="名称", align=2, sort=3)
public String getName() {return name;}
new ExportExcel("数据", xxx.class).setDataList(list).write(response, fileName).dispose();
4.4 POI导入excel
public String import(MultipartFile file) {
String fileName = file.getOriginalFilename();
InputStream is = file.getInputStream();
if(fileName.toLowerCase().endsWith("xls")){
HSSFWorkbook hssfWorkbook = new HSSFWorkbook(is);
sheet1 = hssfWorkbook.getSheetAt(0);
}else if(fileName.toLowerCase().endsWith("xlsx")) {
XSSFWorkbook xssfWorkbook = new XSSFWorkbook(is);
sheet1 = xssfWorkbook.getSheetAt(0);
}
//getLastRowNum 如果sheet中一行数据都没有则返回-1,只有第一行有数据则返回0,最后有数据的行是第n行则返回 n-1;
//getLastCellNum 如果row中一列数据都没有则返回-1,只有第一列有数据则返回1,最后有数据的列是第n列则返回 n;
for (int i = 0; i <= sheet1.getLastRowNum(); i++) {
Row row = sheet1.getRow(i);
for (int j = 0; j < row.getLastCellNum(); j++){
row.getCell((short) j).getStringCellValue();
}
}
//合并单元格的值,就是合并单元格首行首列的值
}
5 POI操作word
5.1 POI操作word常用API
获取文件
HWPFDocument hwpfDocument = new HWPFDocument(); --doc 不建议使用
XWPFDocument xwpfDocument = new XWPFDocument(); --docx
XWPFDocument xwpfDocument = new XWPFDocument(new FileInputStream()); --docx
操作段落 document(文件)=> paragraph(段落) => run
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run=paragraph.createRun();
List paragraphs = document.getParagraphs();
List xwpfRuns = paragraphs .getRuns();
XWPFRun run = xwpfRuns.get(index);
操作表格 document(文件)=> table(段落) => row(行) => cell(单元格)
XWPFTable table = document.createTable();
XWPFTableRow row = table.createRow();
XWPFTableCell cell = row.createCell();
Lis tables = document.getTables();
List rows = table.getRows();
List tableCells = row.getTableCells();
建议大家使用 office word 来创建文档。(wps 和 word 结构有些不一样)
XWPFComment -------------------评论
XWPFFooter -------------------页脚
XWPFFootnotes -------------------脚注
XWPFHeader -------------------页眉
XWPFHyperlink -------------------超链接
XWPFNumbering -------------------编号
XWPFParagraph -------------------段落
XWPFPictureData -------------------图片
XWPFStyles -------------------样式(设置多级标题的时候用)
XWPFTable -------------------表格
5.2 POI导出word——直接导出示例
public void exportWord() {
XWPFDocument document = new XWPFDocument();//文件
XWPFParagraph paragraph;
XWPFRun run;
//建立段落
paragraph = document.createParagraph(); //新建一个标题段落对象(就是一段文字)
paragraph.setAlignment(ParagraphAlignment.CENTER);//样式居中
run = paragraph.createRun(); //创建文本对象
run.setBold(true); //加粗
run.setColor("000000");//设置颜色
run.setFontSize(25); //字体大小
run.setFontFamily("");//设置字体
run.addBreak(); //换行
run.setText("111"); //设置内容
//建立表格
XWPFTable table = document.createTable(8,4);
XWPFTableRow row;
XWPFTableCell cell;
CTTcPr cellPr;//单元格属性
for(int j=0;j<8;j++){
row = table.getRow(j);
row.setHeight(600);
for(int i=0;i<4;i++){//第一行
cell = row.getCell(i);//建立单元格
cell.setText("111"); //设置内容
cellPr = cell.getCTTc().addNewTcPr();//单元格属性
cellPr.addNewTcW().setW(BigInteger.valueOf(5000));//设置宽度
cellPr.addNewVAlign().setVal(STVerticalJc.CENTER);//垂直居中
}
}
}
5.3 POI导出word——模板导出示例
public void exportWord(String templatePath) {
Map<String, String> dataMap = new HashMap<>(); //替换模板数据的map
//模板文件流
InputStream is = new FileInputStream(templatePath);
XWPFDocument doc = new XWPFDocument(is);
//遍历模板表格替换字段
if (doc.getTables() != null){
for (int a = 0; a < doc.getTables().size(); a++) { //循环表格
XWPFTable table = doc.getTables().get(a);
for (int i = 0; i < table.getNumberOfRows(); i++) { //循环行
XWPFTableRow row = table.getRow(i);
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) { //循环单元格
//遍历集合进行替换
for (String key : dataMap.keySet()) { //循环替换数据
if (cell.getText().equals(key)) {
cell.removeParagraph(0);
cell.setText(dataMap.get(key));
//设置样式
CTTcPr tcpr = cell.getCTTc().addNewTcPr();
CTVerticalJc va = tcpr.addNewVAlign();
va.setVal(STVerticalJc.CENTER);
cell.getCTTc().getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
}
}
}
}
}
}
}
5.4 POI导出word——包含图片
推荐使用poi-tl
5.5 POI导入word
段落内容
InputStream is;
XWPFDocument doc = new XWPFDocument(is);
List<XWPFParagraph> paragraphs = doc.getParagraphs();
String text = paragraphs.get(0).getText();
表格内容
public void exportWord(String templatePath) {
Map<String, String> dataMap = new HashMap<>(); //替换模板数据的map
//模板文件流
InputStream is = new FileInputStream(templatePath);
XWPFDocument doc = new XWPFDocument(is);
//遍历模板表格替换字段
if (doc.getTables() != null){
for (int a = 0; a < doc.getTables().size(); a++) { //循环表格
XWPFTable table = doc.getTables().get(a);
for (int i = 0; i < table.getNumberOfRows(); i++) { //循环行
XWPFTableRow row = table.getRow(i);
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) { //循环单元格
cell.getText();
}
}
}
}
}
图片(未测试)
List<XWPFPictureData> allPictures = doc.getAllPictures();
for (XWPFPictureData picture : allPictures) {
byte[] data = picture.getData();
FileOutputStream out;
out.write(data);
out.close();
}
6.poi-tl(word模板)
6.1官网
http://deepoove.com/poi-tl/
6.2 依赖(必须有poi依赖,且注意版本对应)
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.8.2</version>
</dependency>
6.3 介绍
Word模板支持DOCX格式,所有的标签都是以 {{ 开头,以 }} 结尾
6.4 使用
new ExportWord().export(new Object(), templatePath+"//wordTemplate//wordTemplate.docx",response);
public class ExportWord{
public void export(Object object, String templatePath, HttpServletResponse response) throws IOException {
Map<String, Object> mapData = getMapData(saveYearTaskVo);
XWPFTemplate template = XWPFTemplate.compile(templatePath)
.render(mapData);
this.write(template,"xxx.docx");
}
private static Map<String, Object> getMapData(Object object){
Map<String, Object> data = new HashMap<>();
data.put("name", object.getName());
return data;
}
private void write(XWPFTemplate template,HttpServletResponse response, String fileName) throws IOException {
String fileNameURL = URLEncoder.encode(fileName, "UTF-8");
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileNameURL + ";" + "filename*=utf-8''" + fileNameURL);
response.setContentType("application/octet-stream");
//刷新缓冲
response.flushBuffer();
OutputStream ouputStream = response.getOutputStream();
//doc将word写入到response的输出流中,供页面下载该word文件
template.write(ouputStream);
ouputStream.flush();
ouputStream.close();
}
}
6.5 图片模板
// 本地图片
put("localPicture", new PictureRenderData(120, 120, "./sayi.png"));
// 图片流文件
put("localBytePicture", new PictureRenderData(100, 120, ".png", new FileInputStream("./logo.png")));
// 网络图片
put("urlPicture", new PictureRenderData(100, 100, ".png", BytePictureUtils.getUrlBufferedImage("https://avatars3.githubusercontent.com/u/1394854")));
// java 图片
put("bufferImagePicture", new PictureRenderData(100, 120, ".png", bufferImage)));
6.6 表格模板
RowRenderData header = RowRenderData.build(new TextRenderData("FFFFFF", "姓名"), new TextRenderData("FFFFFF", "学历"));
RowRenderData row0 = RowRenderData.build("张三", "研究生");
RowRenderData row1 = RowRenderData.build("李四", "博士");
RowRenderData row2 = RowRenderData.build("王五", "博士后");
put("table", new MiniTableRenderData(header, Arrays.asList(row0, row1, row2)));
7.easypoi
7.1 官网
https://gitee.com/lemur/easypoi
http://doc.wupaas.com/docs/easypoi/easypoi-1c0u4mo8p4ro8
7.2 使用
7.2.1 特点
1.设计精巧,使用简单
2.接口丰富,扩展简单
3.默认值多,write less do more
4.spring mvc支持,web导出可以简单明了
7.2.2 依赖
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>3.2.0</version>
</dependency>
7.2.3 Excel导入导出
Excel的导入导出是Easypoi的核心功能,前期基本也是围绕这个打造的,主要分为三种方式的处理,其中模板和Html目前只支持导出,因为支持Map.class其实导入应该是怎样都支持的
- 注解方式,注解变种方式
- 模板方式
- Html方式
7.2.4 注解方式导出示例
@ExcelTarget("teacherEntity")
public class TeacherEntity implements java.io.Serializable {
/** name */
@Excel(name = "主讲老师")
private String name;
}
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("计算机一班学生","学生"),
StudentEntity .class, list);
- @Excel 作用到filed上面,是对Excel一列的一个描述
- @ExcelCollection 表示一个集合,主要针对一对多的导出,比如一个老师对应多个科目,科目就可以用集合表示
- @ExcelEntity 表示一个继续深入导出的实体,但他没有太多的实际意义,只是告诉系统这个对象里面同样有导出的字段
- @ExcelIgnore 和名字一样表示这个字段被忽略跳过这个导导出
- @ExcelTarget 这个是作用于最外层的对象,描述这个对象的id,以便支持一个对象可以针对不同导出做出不同处理
8.Hutool
https://www.hutool.cn/
https://www.hutool.cn/docs/#/poi/Excel%E7%94%9F%E6%88%90-ExcelWriter?id=%e8%87%aa%e5%ae%9a%e4%b9%89excel
9.总结
注意:
- poi-tl需要依赖poi,注意版本的对应
- easypoi的依赖内部依赖原生的poi
8.1 优劣对比
8.1.1 前端导出
- 优点:操作简单
- 缺点:无法处理复杂样式、复杂数据
8.1.2 poi导入导出
- 优点:能够处理几乎所有的导入导出功能
- 缺点:导入导出的开发流程相对繁琐
8.1.3 poi-tl导出
- 优点:操作简单,能够处理复杂的word导出
- 缺点:只支持word导出
8.1.4 easypoi导入导出
- 优点:操作简单
- 缺点:
8.2 如何选择(个人理解)
- 优先选择前端导出
- 简单导出使用poi(基础)
- 复杂导出使用poi-tl(word)或easypoi
- 无法使用poi-tl或easypoi,回归poi