网页数据导出为Excel(带图片)
将网页数据导出为Excel恐怕是日常开发遇到非常多的需求了,以往的操作可能会稍显复杂,今天学习了一个新的神器,分享给大家,话不多说,上代码
- 我们选用easyExcel作为技术栈,首先引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
- 为了方便操作,我们首先建立一个与Excel对应的实体类
package com.****.energy.nat.entity;
/**
* @author ascool_zh
* @create 2021-02-9:59
*/
@Data
@ContentRowHeight(35)
@HeadRowHeight(20)
public class ExcelModel {
@ExcelProperty(value="条码号",index = 0)
@ColumnWidth(23)
private String barCode;
@ExcelProperty(value="条形码",index = 1)
@ColumnWidth(23)
private File barCodeImg;
}
/**
* ExcelProperty index 指定写到第几列,默认根据成员变量排序。value指定写入的名称,默认成员变量的名字,多个value可以参照快速开始中的复杂头
* ExcelIgnore 默认所有字段都会写入excel,这个注解会忽略这个字段
* DateTimeFormat 日期转换,将Date写到excel会调用这个注解。里面的value参照java.text.SimpleDateFormat
* NumberFormat 数字转换,用Number写excel会调用这个注解。里面的value参照java.text.DecimalFormat
* ExcelIgnoreUnannotated 默认不加ExcelProperty的注解的都会参与读写,加了不会参与
*/
- 写Excel
- 一个简单的例子
@Data
public class DemoData {
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
/**
* 忽略这个字段
*/
@ExcelIgnore
private String ignore;
}
/**
* 指定写入的列
* <p>1. 创建excel对应的实体对象 参照{@link IndexData}
* <p>2. 使用{@link ExcelProperty}注解指定写入的列
* <p>3. 直接写即可
*/
@Test
public void indexWrite() {
//文件名,文件会被存入到这个路径
String fileName = TestFileUtil.getPath() + "indexWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,DemoData,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
}
- 批量写
/**
* 重复多次写入
* <p>
* 1. 创建excel对应的实体对象 参照{@link ComplexHeadData}
* <p>
* 2. 使用{@link ExcelProperty}注解指定复杂的头
* <p>
* 3. 直接调用二次写入即可
*/
@Test
public void repeatedWrite() {
// 方法1 如果写到同一个sheet
String fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
ExcelWriter excelWriter = null;
try {
// 这里 需要指定写用哪个class去写
excelWriter = EasyExcel.write(fileName, DemoData.class).build();
// 这里注意 如果同一个sheet只要创建一次
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来
for (int i = 0; i < 5; i++) {
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
List<DemoData> data = data();
excelWriter.write(data, writeSheet);
}
} finally {
// 千万别忘记finish 会帮忙关闭流
if (excelWriter != null) {
excelWriter.finish();
}
}
// 方法2 如果写到不同的sheet 同一个对象
fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
try {
// 这里 指定文件
excelWriter = EasyExcel.write(fileName, DemoData.class).build();
// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面
for (int i = 0; i < 5; i++) {
// 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样
WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).build();
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
List<DemoData> data = data();
excelWriter.write(data, writeSheet);
}
} finally {
// 千万别忘记finish 会帮忙关闭流
if (excelWriter != null) {
excelWriter.finish();
}
}
// 方法3 如果写到不同的sheet 不同的对象
fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
try {
// 这里 指定文件
excelWriter = EasyExcel.write(fileName).build();
// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面
for (int i = 0; i < 5; i++) {
// 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样。这里注意DemoData.class 可以每次都变,我这里为了方便 所以用的同一个class 实际上可以一直变
WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).head(DemoData.class).build();
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
List<DemoData> data = data();
excelWriter.write(data, writeSheet);
}
} finally {
// 千万别忘记finish 会帮忙关闭流
if (excelWriter != null) {
excelWriter.finish();
}
}
}
- 图片写
@Data
@ContentRowHeight(100)
@ColumnWidth(100 / 8)
public class ImageData {
private File file;
private InputStream inputStream;
/**
* 如果string类型 必须指定转换器,string默认转换成string
*/
@ExcelProperty(converter = StringImageConverter.class)
private String string;
private byte[] byteArray;
/**
* 根据url导出
*
* @since 2.1.1
*/
private URL url;
}
/**
* 图片导出
* <p>
* 1. 创建excel对应的实体对象 参照{@link ImageData}
* <p>
* 2. 直接写即可
*/
@Test
public void imageWrite() throws Exception {
String fileName = TestFileUtil.getPath() + "imageWrite" + System.currentTimeMillis() + ".xlsx";
// 如果使用流 记得关闭
InputStream inputStream = null;
try {
List<ImageData> list = new ArrayList<ImageData>();
ImageData imageData = new ImageData();
list.add(imageData);
String imagePath = TestFileUtil.getPath() + "converter" + File.separator + "img.jpg";
// 放入五种类型的图片 实际使用只要选一种即可
imageData.setFile(new File(imagePath));
inputStream = FileUtils.openInputStream(new File(imagePath));
imageData.setString(imagePath);
imageData.setInputStream(inputStream);
imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath)));
imageData.setUrl(new URL(
"https://raw.githubusercontent.com/alibaba/easyexcel/master/src/test/resources/converter/img.jpg"));
EasyExcel.write(fileName, ImageData.class).sheet().doWrite(list);
} finally {
if (inputStream != null) {
inputStream.close();
}
}
}
- Web写
@RequestMapping("/exportExcel")
public void exportExcel(String startCode, int count, String netCode,String netName,HttpServletResponse response) throws IOException {
//后台查出的数据
List<Map<String, Object>> qryPrintList = printBarcodeService.getPrintList(startCode, count, netCode);
//创建存放ExcelModel的List,你可以理解为一个ExcelModel为一行数据,其属性barCode和barCodeImg即是行所要填的值
List<ExcelModel> list = new ArrayList<ExcelModel>();
String msg = "";
String path = "";
if (count <= 5000) {
for (Map<String, Object> map : qryPrintList) {
msg = (String) map.get("barCode");
path = barcodeFilepath + msg + ".png";
ExcelModel excelModel = new ExcelModel();
try {
//对ExcelModel对象赋值,相当于你填写每行的记录
list.add(excelModel);
//msg和path都已经赋值
excelModel.setBarCode(msg);
excelModel.setBarCodeImg(new File(path));
} catch (Exception e) {
System.out.println(e);
}
}
//设置一些属性
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode(netName+"条码表", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
//执行,list中已经包含多个ExcelModel,即相当于填写了多条记录
EasyExcel.write(response.getOutputStream(), ExcelModel.class).sheet("条码表").doWrite(list);
}
}
//前端避免使用Ajax,直接用window.location.href更方便
function exportExcel(){
var startCode = $("#startCode").val();
var count = $("#count").val();
var netCode = $("#checkNet").val();
var netName = $("#checkNet").combobox('getText');
window.location.href = "nat/print/exportExcel?startCode="+startCode+"&count="+count+"&netCode="+netCode+"&netName="+netName;
}