目录
原生poi
原生poi对excel操作非常灵活。导出的时候可以对特定的数据给上特定的背景颜色,加生备注信息等等。
原生poi导入
InputStream is = null;
try {
is = file.getInputStream();//获取到excel的字节流(读者可以使用自己的方式获取)
XSSFWorkbook xssfWorkbook = new XSSFWorkbook(is);
//第0个sheet
XSSFSheet sheet = xssfWorkbook.getSheetAt(0);
int row sheet.getLastRowNum(); // 获取最大行数索引值
List<String> values = new ArrayList<>();
//0遍历到最后一行
for(int r=0;r<row;r++){
XSSFRow row = sheet.getRow(r);
//获取第R行的第1个数值
String val1 = ExcelUtil.getXSSFCellValue(row.getCell(1));
}
} catch (Exception e) {
e.printStackTrace();
}
原生poi导出
// 创建excel文件对象
XSSFWorkbook wb = new XSSFWorkbook();
// 创建excel的表单对象
Sheet warnDataSheet = wb.createSheet("sheetName");
Sheet allDataSheet = wb.createSheet("sheetName2");
//浅蓝色背景-微软雅黑 10号
CellStyle headStyle = ExcelUtils.getCellStyle(wb, Font.COLOR_NORMAL, IndexedColors.PALE_BLUE.getIndex(), HorizontalAlignment.CENTER);
//白色背景-微软雅黑 10号
CellStyle dataStyle= ExcelUtils.getCellStyle(wb, IndexedColors.BLACK.index, IndexedColors.WHITE.getIndex(),HorizontalAlignment.CENTER)
Row row = sheet.createRow(0);
// 用行对象得到Cell对象
Cell cell = row.createCell(0);
cell.setCellValue("表头01");
cell.setCellStyle(headStyle);
cell = row.createCell(0);
cell.setCellValue("表头02");
cell.setCellStyle(headStyle);
Row row = sheet.createRow( 1);
Cell createCell = row.createCell(0);
createCell.setCellValue("数据1");
createCell.setCellStyle(dataStyle);
createCell = row.createCell(0);
createCell.setCellValue("数据2");
createCell.setCellStyle(dataStyle);
//给数据2加批注
ExcelUtils.addComment(createCell,"批注信息",warnDataSheet );
String fileName = "excel文件名称";
ExcelUtils.exportExcel(response,wb,fileName);
ExcelUtil
public static void exportExcel(HttpServletResponse response, XSSFWorkbook wb,String fileName ) {
try {
fileName = URLEncoder.encode(fileName, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// 设置响应头
response.setCharacterEncoding("utf-8");
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("Content-Disposition",
"attachment;filename=" + fileName+".xls");
try ( ServletOutputStream outputStream = response.getOutputStream()){
wb.write(outputStream);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(wb!=null){
try {
wb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 获取单元格样式
* @param wb workbook
* @param fontColor 字体颜色(IndexedColors.RED.getIndex())
* @param groundColor 背景颜色IndexedColors.CORNFLOWER_BLUE.getIndex()
* @return void
* @date 2022-05-05 09:06:35
*/
public static CellStyle getCellStyle( XSSFWorkbook wb,short fontColor,short groundColor, HorizontalAlignment var1){
CellStyle style = wb.createCellStyle();
XSSFFont font = wb.createFont();
font.setColor(fontColor);
font.setFontName("微软雅黑");
font.setFontHeightInPoints((short)10);
style.setFont(font);
style.setFillForegroundColor(groundColor);
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setBorderBottom(BorderStyle.THIN); //下边框
style.setBorderLeft(BorderStyle.THIN);//左边框
style.setBorderTop(BorderStyle.THIN);//上边框
style.setBorderRight(BorderStyle.THIN);//右边框
style.setAlignment(var1);
return style;
}
/**
* 合并单元格
* @return java.util.Map<java.lang.Integer,org.apache.poi.ss.usermodel.CellStyle>
* @date 2022-05-05 17:04:22
*/
public static void mergedCell(Sheet sheet,int sx,int sy,int tx,int ty){
sheet.addMergedRegion(new CellRangeAddress(sx,sy,tx,ty));
}
/**
* 给Cell添加批注
* @param cell 单元格
* @param value 批注内容
* @date 2022-05-05 17:04:22
*/
public static void addComment(Cell cell, String value, Sheet sheet) {
//设置单元格中的批注
Drawing draw = sheet.createDrawingPatriarch();
//此处八个参数 前四个参数为两个坐标点(从a坐标到b坐标)后四个参数 为 编辑和显示批注时的大小(看需求调整)
Comment comment = draw.createCellComment(new XSSFClientAnchor(1,1,8,8,3,3,5,1));
//输入批注信息
comment.setString(new XSSFRichTextString(value));
//添加作者,选中B5单元格,看状态栏
comment.setAuthor("sys");
//将批注添加到单元格对象中
cell.setCellComment(comment);
}
public static String getXSSFCellValue(XSSFCell xssfCell) {
String cellValue = null;
if (xssfCell != null) {
CellType cellType = xssfCell.getCellType();
if (CellType.STRING.equals(cellType)) {
cellValue = xssfCell.getStringCellValue();
} else if (CellType.NUMERIC.equals(cellType)) {
double d = xssfCell.getNumericCellValue();
cellValue = df.format(d);
} else if (CellType.BOOLEAN.equals(cellType)) {
cellValue = String.valueOf(xssfCell.getBooleanCellValue());
} else if (CellType.FORMULA.equals(cellType)) {
cellValue = String.valueOf(xssfCell.getCellFormula());
}
}
return cellValue;
}
EasyExcel-list集合填充excel导出
public void exportIndExcel(HttpServletResponse response, List<String> indIds) throws IOException {
try {
String fileName = URLEncoder.encode("指标填报模板", "UTF-8");
if(indIds!=null&&indIds.size()>0){
fileName = URLEncoder.encode("指标数据表", "UTF-8");
}
/* getIndDefData返回数据如下 List<List<String>> 对于行列数据
List<List<String>> dataOne = new ArrayList<>();
List<List<String>> dataTwo = new ArrayList<>();
Map<String,List<List<String>>> value = new HashMap<>();*/
Map<String, List<List<String>>> map = getIndDefData(indIds);
List<List<String>> datasOne = map.get("dataOne");
List<List<String>> datasTwo = map.get("dataTwo");
/*getIndDefHeaders返回数据
List<List<String>> heads= new ArrayList<>();
List<String> column0 = new ArrayList<>();
column0.add("指标目录");
heads.add(column0);
List<String> column4 = new ArrayList<>();
column4.add("指标类型");
heads.add(column4); */
List<List<String>> headersOne = getIndDefHeaders(1);
List<List<String>> headersTwo = getIndDefHeaders(2);
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
ExcelWriterBuilder writerBuilder = EasyExcel.write(response.getOutputStream());
ExcelWriter build = writerBuilder.build();
WriteSheet one = EasyExcel.writerSheet(0, "基础指标").head(headersOne).build();
WriteSheet two = EasyExcel.writerSheet(1, "衍生指标").head(headersTwo).build();
build.write(datasOne,one);
build.write(datasTwo,two);
build.finish();
} catch (Exception e) {
}
}
根据对象读写
对象
public class DemoData {
/**
* 强制读取第三个 这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配
*/
@ExcelProperty(index = 2)
private Double doubleData;
/**
* 用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段读取到数据
*/
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
}
监听器
监听器构造器可以传对象进来,
list获取读取的数据,
xxxService对数据进行保存
// 如果没有特殊说明,下面的案例将默认使用这个监听器
public class DemoDataListener extends AnalysisEventListener<DemoData> {
List<DemoData> list = new ArrayList<DemoData>();
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*/
public DemoDataListener() {
}
/**
* 这个每一条数据解析都会来调用
*
* @param data
* @param context
*/
@Override
public void invoke(DemoData data, AnalysisContext context) {
ReadSheetHolder readSheetHolder = analysisContext.readSheetHolder();
String sheetName = readSheetHolder.getSheetName()
//sheetName sheet名称
System.out.println("解析到一条数据:{}", JSON.toJSONString(data));
list.add(data);
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println(JSON.toJSONString(list));
}
}
导入导出
简单例子
/**
excel文件的下载
*/
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("指标数据表", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
// data()方法是写入的数据,结果是List<DemoData>集合
EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
}
/**
excel文件的上传
*/
@PostMapping("upload")
@ResponseBody
public String upload(MultipartFile file) throws IOException {
EasyExcel.read(file.getInputStream(), DemoData.class, new DemoDataListener()).sheet().doRead();
return "success";
}
导入多个sheet
@Test
public void repeatedRead() {
String fileName = "demo.xlsx";
// 读取全部sheet
// 这里需要注意 DemoDataListener的doAfterAllAnalysed 会在每个sheet读取完毕后调用一次。然后所有sheet都会往同一个DemoDataListener里面写
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).doReadAll();
// 读取部分sheet
fileName = "demo.xlsx";
ExcelReader excelReader = EasyExcel.read(fileName).build();
// 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener
// readSheet参数设置读取sheet的序号
ReadSheet readSheet1 =
EasyExcel.readSheet(0).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
ReadSheet readSheet2 =
EasyExcel.readSheet(1).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
// 这里注意 一定要把sheet1 sheet2 一起传进去,不然有个问题就是03版的excel 会读取多次,浪费性能
excelReader.read(readSheet1, readSheet2);
// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
excelReader.finish();
}
导出多个sheet
@GetMapping("/test")
public void testExport(HttpServletResponse response) throws IOException {
String fileName = URLEncoder.encode("指标填报模板", "UTF-8");
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
ExcelWriter build1 = EasyExcel.write(response.getOutputStream(), DownloadData.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet(1,"sheet01").build();
WriteSheet writeSheet02 = EasyExcel.writerSheet(2,"sheet02").build();
List<DownloadData> data1 = new ArrayList<>();
//省略数据
List<DownloadData> data2 = new ArrayList<>();
//省略数据
//sheet00 第一页
build1.write(data1,writeSheet);
//sheet01 第二页
build1.write(data2,writeSheet02);
build1.finish();
}
导出指定列
@Test
public void excludeOrIncludeWrite() {
String fileName = "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx";
// 忽略 date 不导出
Set<String> excludeColumnFiledNames = new HashSet<String>();
excludeColumnFiledNames.add("date");
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoData.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet("忽略date")
.doWrite(data());
fileName = "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx";
// 根据用户传入字段 假设我们只要导出 date
Set<String> includeColumnFiledNames = new HashSet<String>();
includeColumnFiledNames.add("date");
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoData.class).includeColumnFiledNames(includeColumnFiledNames).sheet("导出date")
.doWrite(data());
}
导入列 (根据index控制)
public class IndexData {
/**
* 导出的excel第二列和第四列将空置
*/
@ExcelProperty(value = "字符串标题", index = 0)
private String string;
@ExcelProperty(value = "日期标题", index = 2)
private Date date;
@ExcelProperty(value = "数字标题", index = 4)
private Double doubleData;
}
复杂头信息
public class ComplexHeadData {
/**
* 主标题 将整合为一个单元格效果如下:
* —————————————————————————
* | 主标题 |
* —————————————————————————
* |字符串标题|日期标题|数字标题|
* —————————————————————————
*/
@ExcelProperty({"主标题", "字符串标题"})
private String string;
@ExcelProperty({"主标题", "日期标题"})
private Date date;
@ExcelProperty({"主标题", "数字标题"})
private Double doubleData;
}