以下代码都是自身写出来实际验证过的.跟类似百度知道, 优快云 那种渣渣文是不同的.
导入:
所需 jar包
<!--apache poi-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>复制代码
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.util.StringUtil;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
public class ExcelReader {
private POIFSFileSystem fs;
private HSSFWorkbook wb;
private HSSFSheet sheet;
private HSSFRow row;
private XSSFWorkbook xFwb;
private XSSFSheet xFSheet;
private XSSFRow xFRow;
private int sheetSize = 0;
public void setSheetSize(int sheetSize) {
this.sheetSize = sheetSize;
}
/**
* 自我关闭输入流
*
* @param excelPath
* @param inputStream
* WARNING:inputStream can not be repeatable!!!
* @return
* @throws IOException
*/
public LinkedList<String> readExcelTitleSafeLy(String excelPath, InputStream inputStream) throws IOException {
LinkedList<String> title = new LinkedList<>();
try {
title = readExcelTitle(excelPath, inputStream);
} finally {
IOUtils.closeQuietly(inputStream);
}
return title;
}
/**
* 自我关闭输入流
*
* @param excelPath
* @param inputStream
* WARNING:inputStream can not be repeatable!!!
* @return
* @throws IOException
*/
public Map<Integer, LinkedList<String>> readExcelContentSafeLy(String excelPath, InputStream inputStream) throws IOException {
Map<Integer, LinkedList<String>> content = new LinkedHashMap<>();
try {
content = readExcelContent(excelPath, inputStream);
} finally {
IOUtils.closeQuietly(inputStream);
}
return content;
}
/**
* 读取 xls Excel表格表头的内容
*
* @param excelPath
* @param inputStream
* WARNING:inputStream can not be repeatable!!! AND this method can
* not be close stream;
* @return String 表头内容的数组
*/
public LinkedList<String> readExcelTitle(String excelPath, InputStream inputStream) throws IOException {
boolean isXLS = setPublicAndJudge(excelPath, inputStream);
LinkedList<String> title = new LinkedList<>();
// 标题总列数
int colNum;
String cellFormatValue;
if (isXLS) {
colNum = row.getPhysicalNumberOfCells();
for (int i = 0; i < colNum; i++) {
cellFormatValue = getCellFormatValue(row.getCell(i));
// 如果是空表头就直接 空+ index
if (StringUtils.isEmpty(cellFormatValue)) {
title.add("空" + i);
} else {
title.add(cellFormatValue);
}
}
} else {
// 标题总列数
colNum = xFRow.getPhysicalNumberOfCells();
for (int i = 0; i < colNum; i++) {
cellFormatValue = getCellFormatValue(xFRow.getCell((short) i));
// 如果是空表头就直接 空+ index
if (StringUtils.isEmpty(cellFormatValue)) {
title.add("空" + i);
} else {
title.add(cellFormatValue);
}
}
}
return title;
}
private boolean setPublicAndJudge(String excelPath, InputStream inputStream) throws IOException {
boolean isXLS = false;
if (StringUtils.endsWithIgnoreCase(excelPath, "xls")) {
fs = new POIFSFileSystem(inputStream);
wb = new HSSFWorkbook(fs);
sheet = wb.getSheetAt(sheetSize);
// 得到表头
row = sheet.getRow(0);
isXLS = true;
} else if (StringUtils.endsWithIgnoreCase(excelPath, "xlsx")) {
xFwb = new XSSFWorkbook(inputStream);
xFSheet = xFwb.getSheetAt(0);
// 得到表头
xFRow = xFSheet.getRow(0);
} else {
throw new RuntimeException("未能识别的后缀!");
}
return isXLS;
}
/**
* 读取 Excel 的实际数据,从第二行开始
*
* @param excelPath
* @param inputStream
* WARNING:inputStream can not be repeatable!!!
* @return
* @throws IOException
*/
@SuppressWarnings("deprecation")
public Map<Integer, LinkedList<String>> readExcelContent(String excelPath, InputStream inputStream)
throws IOException {
boolean isXLS = setPublicAndJudge(excelPath, inputStream);
// 得到总行数
int rowNum;
// 总列数
int colNum;
// data
LinkedList<String> rowCells;
// 第几行, data
Map<Integer, LinkedList<String>> content = new LinkedHashMap<>();
if (isXLS) {
// 得到总行数
rowNum = sheet.getLastRowNum();
// 得到总列数
colNum = row.getPhysicalNumberOfCells();
// 正文内容应该从第二行开始,第一行为表头的标题
for (int i = 1; i <= rowNum; i++) {
rowCells = new LinkedList<>();
row = sheet.getRow(i);
int j = 0;
while (j < colNum) {
if (Objects.nonNull(xFRow)
&& StringUtils.isNotBlank(getCellFormatValue(row.getCell((short) j)).trim())) {
rowCells.add(getCellFormatValue(row.getCell((short) j)).trim());
} else {
rowCells.add(StringUtils.EMPTY);
}
j++;
}
// 如果第一列是空的就不加入
if (StringUtils.isEmpty(rowCells.getFirst())) {
continue;
}
content.put(i - 1, rowCells);
}
} else {
// 得到总行数
rowNum = xFSheet.getLastRowNum();
// 总列数
colNum = xFRow.getPhysicalNumberOfCells();
// 正文内容应该从第二行开始,第一行为表头的标题
for (int i = 1; i <= rowNum; i++) {
rowCells = new LinkedList<>();
xFRow = xFSheet.getRow(i);
int j = 0;
while (j < colNum) {
if (Objects.nonNull(xFRow)
&& StringUtils.isNotBlank((getCellFormatValue(xFRow.getCell((short) j)).trim()))) {
rowCells.add(getCellFormatValue(xFRow.getCell((short) j)).trim());
} else {
rowCells.add(StringUtils.EMPTY);
}
j++;
}
// 如果第一列是空的就不加入
if (StringUtils.isEmpty(rowCells.getFirst())) {
continue;
}
content.put(i - 1, rowCells);
}
}
return content;
}
/**
* 根据HSSFCell类型设置数据 处理2003的xls Excel
*
* @param cell
* @return
*/
private String getCellFormatValue(HSSFCell cell) {
if (Objects.isNull(cell)) {
return StringUtils.EMPTY;
}
String cellValue;
// 判断当前Cell的Type
switch (cell.getCellType()) {
// 如果当前Cell的Type为NUMERIC
case HSSFCell.CELL_TYPE_NUMERIC:
cellValue = handleNUMERICCellValue(cell);
break;
case HSSFCell.CELL_TYPE_FORMULA: {
cellValue = handleDate(cell);
break;
}
// 如果当前Cell的Type为STRIN
case HSSFCell.CELL_TYPE_STRING:
// 取得当前的Cell字符串
cellValue = cell.getRichStringCellValue().getString();
break;
// 默认的Cell值
default:
cellValue = StringUtils.EMPTY;
}
return cellValue;
}
private String handleNUMERICCellValue(Cell cell) {
String cellValue;
// 当前值
Object inputVal;
if (HSSFDateUtil.isCellDateFormatted(cell)) {
SimpleDateFormat sdf;
if (cell.getCellStyle().getDataFormat() == HSSFDataFormat.getBuiltinFormat("h:mm")) {
sdf = new SimpleDateFormat("HH:mm");
} else {// 日期
sdf = new SimpleDateFormat("yyyy-MM-dd");
}
Date date = cell.getDateCellValue();
cellValue = sdf.format(date);
} else {
double doubleVal = cell.getNumericCellValue();
long longVal = Math.round(cell.getNumericCellValue());
if (Double.parseDouble(longVal + ".0") == doubleVal) {
inputVal = longVal;
} else {
inputVal = doubleVal;
}
cellValue = String.valueOf(inputVal);
}
return cellValue;
}
private String handleDate(Cell cell) {
String cellValue;
// 判断当前的cell是否为Date
if (HSSFDateUtil.isCellDateFormatted(cell)) {
SimpleDateFormat sdf;
if (cell.getCellStyle().getDataFormat() == HSSFDataFormat.getBuiltinFormat("h:mm")) {
sdf = new SimpleDateFormat("HH:mm");
} else {// 日期
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
Date date = cell.getDateCellValue();
cellValue = sdf.format(date);
}
// 如果是纯数字
else {
DecimalFormat df = new DecimalFormat("#");
// 取得当前Cell的数值
cellValue = String.valueOf(df.format(cell.getNumericCellValue()));
}
return cellValue;
}
/**
* 根据XSSFCell类型设置数据
*
* @param cell
* @return
*/
private String getCellFormatValue(XSSFCell cell) {
if (Objects.isNull(cell)) {
return StringUtils.EMPTY;
}
String cellValue;
// 判断当前Cell的Type
switch (cell.getCellType()) {
// 如果当前Cell的Type为NUMERIC
case XSSFCell.CELL_TYPE_NUMERIC:
cellValue = handleNUMERICCellValue(cell);
break;
// 公式型
case XSSFCell.CELL_TYPE_FORMULA: {
cellValue = handleDate(cell);
break;
}
// 如果当前Cell的Type为STRIN
case HSSFCell.CELL_TYPE_STRING:
// 取得当前的Cell字符串
cellValue = cell.getRichStringCellValue().getString();
break;
// 默认的Cell值
default:
cellValue = StringUtils.EMPTY; } return cellValue; }}
复制代码
导出:
动态导出(支持自定义表头,内容)
所需 jar包:
core:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.5</version>
</dependency>
other:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
复制代码
import com.google.common.base.Charsets;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.util.IOUtils;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
/**
* support Dynamic Head content
* 此种导出方式不建议大量数据使用,因为是先把数据放置内存,最后集中处理的!!!
* @author Forest10
* @date 2018/3/28 10:57
*/
@Data
public class DynamicExcelWriter {
/***
* 导出的文件名字
*/
private String fileName;
/****should be LinkedList****/
private LinkedList<String> excelHeadList;
/****should be LinkedList****/
private LinkedList<LinkedList<String>> excelContentList;
public DynamicExcelWriter(LinkedList<String> excelHeadList, LinkedList<LinkedList<String>> excelContentList) {
this.excelHeadList = excelHeadList;
this.excelContentList = excelContentList;
}
/***导出表头**/
private void exportHead(CSVPrinter csvPrinter) throws IOException {
//Assert.check(CollectionUtils.isNotEmpty(excelHeadList), "excel表头不能为空!");
csvPrinter.printRecord(CollectionUtils.isEmpty(excelHeadList) ? new LinkedList<>() : excelHeadList);
csvPrinter.flush();
}
/***导出内容**/
private void exportContent(CSVPrinter csvPrinter) throws IOException {
//Assert.check(CollectionUtils.isNotEmpty(excelHeadList), "excel内容不能为空!");
if (CollectionUtils.isEmpty(excelContentList)) {
excelContentList = new LinkedList<>();
}
for (List<String> list : excelContentList) {
csvPrinter.printRecord(CollectionUtils.isEmpty(list) ? new LinkedList<>() : list);
//flush 每行
csvPrinter.flush();
}
//flush所有行
csvPrinter.flush();
}
/**
* 导出Excel
*
* @param response
* @throws IOException
*/
public void doExport(HttpServletResponse response) throws IOException {
OutputStream os = null;
CSVPrinter csvPrinter = null;
try {
os = response.getOutputStream();
csvPrinter = new CSVPrinter(new OutputStreamWriter(os, Charsets.UTF_8), CSVFormat.EXCEL);
//设置下载头(csv)
responseSetProperties(response);
//设置 BOM头
os.write(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF});
//导出 excel表头
exportHead(csvPrinter);
//导出实际数据
exportContent(csvPrinter);
} finally {
IOUtils.closeQuietly(os);
IOUtils.closeQuietly(csvPrinter);
}
}
private void responseSetProperties(HttpServletResponse response) throws UnsupportedEncodingException {
// 设置文件后缀
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String fn = StringUtils.isBlank(fileName) ? StringUtils.EMPTY : fileName + sdf.format(new Date()) + ".csv";
// 读取字符编码
String utf = "UTF-8";
// 设置响应
response.setContentType("text/csv;charset=utf-8");
response.setCharacterEncoding(utf);
response.setHeader("Pragma", "public");
response.setHeader("Cache-Control", "max-age=30");
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fn, utf));
}
}复制代码