前言
之前在博客中有一篇是利用POI封装的一个Excel导入导出的框架,由于最近自己也在弄。只是封装的框架用不上,因为字段这些都是动态生成的,没有实体类加注解,所以重新做了一个,比较简单。
本来不太喜欢把介绍什么的说的太多,大家可以去POI官网看文档,也可以去这个博客说的还是比较明白的《JavaWEB–POI之EXCEL操作、优化、封装详解系列(一)–概述与原理》
直接上工具类
import com.uhope.data.export.constants.ExcelConstant;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
/**
* @Author: ChenBin
* @Date: 2018/5/3/0003 11:37
*/
public class ExportUtil {
/**
* 生成excel模板
*
* @param list 模板字段集合
* @return excel
*/
public static Workbook export(List<HashMap<String, Object>> list) {
Workbook workbook = new HSSFWorkbook();
Sheet sheet = workbook.createSheet();
Row row = sheet.createRow(0);
CellStyle cellStyle = workbook.createCellStyle();
DataFormat format = workbook.createDataFormat();
cellStyle.setDataFormat(format.getFormat("@"));
for (int i = 0; i < list.size(); i++) {
sheet.setDefaultColumnWidth((short) 15);
sheet.setDefaultColumnStyle(i, cellStyle);
Cell cell = row.createCell(i);
cell.setCellValue(list.get(i).get("name").toString());
isRed(workbook, cell, (Boolean) list.get(i).get("bool"));
}
return workbook;
}
/**
* 导出Excel模块
* @param response
* @param templateName
* @param list
*/
public static void export(HttpServletResponse response, String templateName, List<HashMap<String, Object>> list){
Workbook workbook = export(list);
try {
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
response.addHeader("Content-Disposition", "attachment;filename=" + new String((templateName + "模版").getBytes(), "ISO-8859-1") + ".xls");
OutputStream os = response.getOutputStream();
workbook.write(os);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 字段飞空则字体颜色为红色
*
* @param workbook 当前excel
* @param cell 单元格
* @param flag 是否非空校验
*/
private static void isRed(Workbook workbook, Cell cell, boolean flag) {
if (flag) {
setFont(workbook, cell, null, ExcelConstant.COLOR_RED);
} else {
setFont(workbook, cell);
}
}
/**
* 设置字体格式和颜色 默认微软雅黑 默认颜色黑色
*
* @param workbook 当前excel
* @param cell 单元格
*/
private static void setFont(Workbook workbook, Cell cell) {
setFont(workbook, cell, null, null);
}
/**
* 设置字体格式和颜色
*
* @param workbook 当前excel
* @param cell 单元格
* @param fontName 字体格式 默认微软雅黑
* @param color 字体颜色 默认黑色
*/
private static void setFont(Workbook workbook, Cell cell, String fontName, Short color) {
fontName = fontName == null ? ExcelConstant.FONTNAME : fontName;
color = color == null ? ExcelConstant.COLOR_BLACK : color;
CellStyle style = workbook.createCellStyle();
DataFormat format = workbook.createDataFormat();
style.setDataFormat(format.getFormat("@"));
style.setFillForegroundColor(IndexedColors.AQUA.getIndex());
style.setAlignment(HorizontalAlignment.CENTER);
Font font = workbook.createFont();
font.setFontName(fontName);
font.setFontHeightInPoints((short) 12);
font.setColor(color);
style.setFont(font);
cell.setCellStyle(style);
}
/**
* 数据导入
*
* @param multipartFile 文件流
* @param size 有多少单元格大小
* @return 数据集合
*/
public static List<List<String>> importExcel(MultipartFile multipartFile, int size) {
Workbook workbook = null;
try {
workbook = getWorkBook(multipartFile.getInputStream(), multipartFile.getOriginalFilename());
} catch (IOException e) {
e.printStackTrace();
}
List<Sheet> sheets = getSheets(workbook);
return readExcel(sheets,size);
}
/**
* 判断获取不同版本的Workbook实现类
*
* @param stream 文件流
* @param path 文件全称
* @return Workbook对象
*/
private static Workbook getWorkBook(InputStream stream, String path) {
Workbook workbook = null;
try {
workbook = path.endsWith(".xls") ? (new HSSFWorkbook(stream))
: (path.endsWith(".xlsx") ? (new XSSFWorkbook(stream)) : (null));
} catch (IOException e) {
e.printStackTrace();
}
return workbook;
}
/**
* 获取每一个sheet,以防有多sheet情况
*
* @param book Workbook对象
* @return sheet集合
*/
private static List<Sheet> getSheets(Workbook book) {
int numberOfSheets = book.getNumberOfSheets();
List<Sheet> sheets = new ArrayList<>();
for (int i = 0; i < numberOfSheets; i++) {
sheets.add(book.getSheetAt(i));
}
return sheets;
}
/**
* 解析导入的文件数据
*
* @param sheets sheet集合
* @return 解析后的数据
*/
private static List<List<String>> readExcel(List<Sheet> sheets,int size) {
List<List<String>> dataList = new ArrayList<>();
for (int i = 0; i < sheets.size(); i++) {
Sheet sheet = sheets.get(i);
if (sheet.getLastRowNum() >= 1) {
System.out.println("=======" + sheet.getSheetName() + "=======");
}
Iterator<Row> sheetIterator = sheet.rowIterator();
while (sheetIterator.hasNext()) {
Row row = sheetIterator.next();
if (row == null) {
continue;
}
List<String> data = new ArrayList<>();
for (int j = row.getFirstCellNum(); j < size; j++) {
Cell cell = row.getCell(j);
if (cell != null){
cell.setCellType(CellType.STRING);
data.add(cell.getStringCellValue());
}else {
data.add("");
}
}
dataList.add(data);
}
}
return dataList;
}
}
说明
工具类是动态生成标题以及标题字体的,为什么呢,因为数据导出之后,有些必填项什么的就是红色的字体,标题是根据传入的值进行生成,这个工具类还可以直接实现导出代码,不必再写请求头,导出的默认是.xls
的格式,有数据的单元格都是文本格式;
导入的方法会根据文件后缀进行判断是做哪个格式的方法操作,遍历所有sheet,在readExcel
方法中有个size
参数,这个参数用来做数据行最后一个单元用的,防止有些格式少了一个单元格数据而长度超出,可以根据业务逻辑装入一个list.size
也行,导入里没有格式转换,因为导出的时候全都是文本格式了,为了业务需求,需要将标题和数据做个区分,所以多创建了一个List data
,将解析出来的每一行每个单元格数据都add
,这样通过下标取出,get(0)
就是第一行的所有标题,其余的就是数据。