3.4.3 文件下载
🍀 编写实体类并创建对象以便写入表格
import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; /** * 学生实体类 * lombok:通过一个插件 + 一个依赖 ,就可以在编译的时候自动帮助生成实体类常用方法 * 注解 @ContentRowHeight():内容的行高 * 注解 @HeadRowHeight:表头的行高 * * @author 狐狸半面添 * @create 2023-02-26 14:56 */ @Data @NoArgsConstructor @AllArgsConstructor public class Student { /** * id */ @ExcelIgnore private String id; /** * 学生姓名 */ @ExcelProperty("学生姓名") private String name; /** * 学生性别 */ @ExcelProperty("学生性别") private String gender; /** * 学生出生日期 */ @ExcelProperty("学生出生日期") private Date birthday; }
🍀 将数据写入到响应体实现下载
/** * 文件下载 * 1. 编写实体类并创建对象以便写入表格 * 2. 设置响应参数:文件的ContentType和文件名,同时设置编码避免乱码 * 3. 直接写,内部会调用finish方法自动关闭OutputStream */ @GetMapping("/download") public void download(HttpServletResponse response) throws IOException { response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); // 防止中文乱码:import java.net.URLEncoder String fileName = URLEncoder.encode("测试", "UTF-8"); response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + fileName + ".xlsx"); // 创建文件簿 ExcelWriterBuilder workBook = EasyExcel.write(response.getOutputStream(), Student.class); // 创建一个文件表 ExcelWriterSheetBuilder sheet = workBook.sheet("模板"); // 生成测试数据 ArrayList<Student> students = new ArrayList<Student>(); for (int i = 1; i <= 10; i++) { students.add(new Student(null, "逐浪者-" + i, "男", new Date())); } // 写入,并且会关闭流 sheet.doWrite(students); }
🍀 浏览器测试
💻 访问:http://localhost:8080/student/download
3.5 自定义单元格样式
EasyExcel支持调整行高、列宽、背景色、字体大小等内容,但是控制方式与使用原生POI无异,比较繁琐,不建议使用。
但是可以使用模板填充的方式,向预设样式的表格中直接写入数据,写入数据的时候会保持原有样式。
4.填充
4.1 填充一组数据
🍀 准备模板
Excel表格中用{} 来表示包裹要填充的变量,如果单元格文本中本来就有{
、}
左右大括号,需要在括号前面使用斜杠转义\{
、\}
。
代码中被填充数据的实体对象的成员变量名或被填充map集合的key需要和Excel中被{}包裹的变量名称一致。
🍀 封装数据
编写封装填充数据的类或选用Map
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * 使用实体类封装填充数据 * 实体中成员变量名称需要和Excel表各种{}包裹的变量名匹配 * * @author 狐狸半面添 * @create 2023-02-26 17:32 */ @Data @NoArgsConstructor @AllArgsConstructor public class FillData { /** * 姓名 */ private String name; /** * 年龄 */ private int age; }
🍀 填充
准备数据并填充到文件
/** * 单组数据填充:封装类的方式 */ @Test public void test03() { // 1.准备模板 String templatePath = FillData.class.getResource("/fill_data_template1.xlsx").getPath(); // 2.创建一个工作簿对象 ExcelWriterBuilder writeWorkBook = EasyExcel.write("excel填充-单组数据.xlsx", FillData.class) .withTemplate(templatePath); // 3.创建工作表对象 ExcelWriterSheetBuilder sheet1 = writeWorkBook.sheet("sheet1"); // 4.准备数据 FillData fillData = new FillData("逐浪者", 19); // 5.填充数据,并关闭流 sheet1.doFill(fillData); } /** * 单组数据填充:map的方式 */ @Test public void test04() { // 1.准备模板 String templatePath = FillData.class.getResource("/fill_data_template1.xlsx").getPath(); // 2.创建一个工作簿对象 ExcelWriterBuilder writeWorkBook = EasyExcel.write("excel填充-单组数据.xlsx", FillData.class) .withTemplate(templatePath); // 3.创建工作表对象 ExcelWriterSheetBuilder sheet1 = writeWorkBook.sheet("sheet1"); // 4.准备数据:使用Map数据填充 HashMap<String, Object> mapFillData = new HashMap<>(); mapFillData.put("name", "狐狸半面添"); mapFillData.put("age", 18); // 5.填充数据,并关闭流 sheet1.doFill(mapFillData); }
🍀 测试效果
4.2 填充多组数据
🍀 准备模板
Excel表格中用{.}
来表示包裹要填充的变量,如果单元格文本中本来就有{
、}
左右大括号,需要在括号前面使用斜杠转义\{
、\}
。
代码中被填充数据的实体对象的成员变量名或被填充map集合的key需要和Excel中被{}包裹的变量名称一致。
🍀 封装数据
编写封装填充数据的类或选用Map
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * 使用实体类封装填充数据 * 实体中成员变量名称需要和Excel表各种{}包裹的变量名匹配 * * @author 狐狸半面添 * @create 2023-02-26 17:32 */ @Data @NoArgsConstructor @AllArgsConstructor public class FillData { /** * 姓名 */ private String name; /** * 年龄 */ private int age; }
🍀 填充
准备数据并填充到文件
/** * 多组数据填充:封装类的方式 */ @Test public void test05() { // 1.准备模板 String templatePath = FillData.class.getResource("/fill_data_template2.xlsx").getPath(); // 2.创建一个工作簿对象 ExcelWriterBuilder writeWorkBook = EasyExcel.write("excel填充-多组数据.xlsx", FillData.class) .withTemplate(templatePath); // 3.创建工作表对象 ExcelWriterSheetBuilder sheet1 = writeWorkBook.sheet("sheet1"); // 4.准备数据 ArrayList<FillData> data = new ArrayList<>(); for (int i = 15; i <= 30; i++) { data.add(new FillData("逐浪者-" + i, i)); } // 5.填充数据,并关闭流 sheet1.doFill(data); }
🍀 测试效果
4.3 组合填充
🍀 准备模板
即有多组数据填充,又有单一数据填充,为了避免两者数据出现冲突覆盖的情况,在多组填充时需要通过FillConfig
对象设置换行。
🍀 封装数据
编写封装填充数据的类或选用Map
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * 使用实体类封装填充数据 * 实体中成员变量名称需要和Excel表各种{}包裹的变量名匹配 * * @author 狐狸半面添 * @create 2023-02-26 17:32 */ @Data @NoArgsConstructor @AllArgsConstructor public class FillData { /** * 姓名 */ private String name; /** * 年龄 */ private int age; }
🍀 填充
准备数据并填充到文件
/** * 组合数据填充 */ @Test public void test06() { // 1.准备模板 String templatePath = FillData.class.getResource("/fill_data_template3.xlsx").getPath(); // 2.创建一个工作簿对象 ExcelWriter workBook = EasyExcel.write("excel填充-组合数据.xlsx", FillData.class) .withTemplate(templatePath).build(); // 3.创建工作表对象 WriteSheet sheet = EasyExcel.writerSheet().build(); // 组合填充时,因为多组填充的数据量不确定,需要在多组填充完之后另起一行 FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build(); // 4.准备数据 ArrayList<FillData> data = new ArrayList<>(); for (int i = 15; i <= 30; i++) { data.add(new FillData("逐浪者-" + i, i)); } HashMap<String, String> dateAndTotal = new HashMap<>(); dateAndTotal.put("date", "2023-02-26"); dateAndTotal.put("total", "10000"); // 5.填充数据,会一并关闭流 // sheet1.doFill(data); // 多组填充 workBook.fill(data, fillConfig, sheet); // 单组填充 workBook.fill(dateAndTotal, sheet); // 关闭流 workBook.finish(); }
🍀 测试效果
4.4 水平填充
🍀 准备模板
水平填充和多组填充模板一样,不一样的地方在于,填充时需要通过FillConfig
对象设置水平填充。
🍀 封装数据
编写封装填充数据的类或选用Map
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * 使用实体类封装填充数据 * 实体中成员变量名称需要和Excel表各种{}包裹的变量名匹配 * * @author 狐狸半面添 * @create 2023-02-26 17:32 */ @Data @NoArgsConstructor @AllArgsConstructor public class FillData { /** * 姓名 */ private String name; /** * 年龄 */ private int age; }
🍀 填充
准备数据并填充到文件
/** * 水平填充 */ @Test public void test07() { // 1.准备模板 String templatePath = FillData.class.getResource("/fill_data_template4.xlsx").getPath(); // 2.创建一个工作簿对象 ExcelWriter workBook = EasyExcel.write("excel填充-水平填充.xlsx", FillData.class) .withTemplate(templatePath).build(); // 3.创建工作表对象 WriteSheet sheet = EasyExcel.writerSheet().build(); // 4.数据准备 ArrayList<FillData> data = new ArrayList<>(); for (int i = 15; i <= 30; i++) { data.add(new FillData("逐浪者-" + i, i)); } // 换行 FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build(); // 多组填充 workBook.fill(data, fillConfig, sheet); // 关闭流 workBook.finish(); }
🍀 测试效果
4.5 注意事项
为了节省内存,所以没有采用把整个文档在内存中组织好之后再整体写入到文件的做法,而是采用的是一行一行写入的方式,不能实现删除和移动行,也不支持备注写入。多组数据写入的时候,如果需要新增行,只能在最后一行增加,不能在中间位置添加。
4.6 填充综合练习
/** * 报表导出 */ @Test public void test08() { // 1.准备模板 String templatePath = FillData.class.getResource("/report_template.xlsx").getPath(); // 2.创建一个工作簿对象 ExcelWriter workBook = EasyExcel.write("报表.xlsx", FillData.class) .withTemplate(templatePath).build(); // 3.创建工作表对象 WriteSheet sheet = EasyExcel.writerSheet().build(); // ****** 准备数据 ******* // 日期 HashMap<String, String> dateMap = new HashMap<>(); dateMap.put("date", "2020-03-16"); // 总会员数 HashMap<String, String> totalCountMap = new HashMap<>(); dateMap.put("totalCount", "1000"); // 新增员数 HashMap<String, String> increaseCountMap = new HashMap<>(); dateMap.put("increaseCount", "100"); // 本周新增会员数 HashMap<String, String> increaseCountWeekMap = new HashMap<>(); dateMap.put("increaseCountWeek", "50"); // 本月新增会员数 HashMap<String, String> increaseCountMonthMap = new HashMap<>(); dateMap.put("increaseCountMonth", "100"); // 新增会员数据 List<Student> students = new ArrayList<>(); for (int i = 1; i <= 10; i++) { students.add(new Student(null, "逐浪者-" + i, "男", new Date())); } // **** 准备数据结束**** // 写入统计数据 workBook.fill(dateMap, sheet); workBook.fill(totalCountMap, sheet); workBook.fill(increaseCountMap, sheet); workBook.fill(increaseCountWeekMap, sheet); workBook.fill(increaseCountMonthMap, sheet); // 写入新增会员 workBook.fill(students, sheet); // 关闭流 workBook.finish(); }