【poi导出excel模板——通过建造者模式+策略模式+函数式接口实现】

poi导出excel模板------通过建造者模式+策略模式+函数式接口实现

poi导出excel示例

首先我们现看一下poi如何导出excel,这里举个例子:目前想要导出一个Map<sex,List>信息,sex作为一个sheet页,Person信息包含姓名、年龄、籍贯等,在Person下还有一个List属性,里面包含名称、时长等,这里需要通过http的response导出文件

代码如下:

java 复制代码
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;

public class ExcelExportExample {
    public static void exportToResponse(Map<String, List<Person>> data, HttpServletResponse response) {
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); // 对于.xlsx格式
            // 或者使用 response.setContentType("application/vnd.ms-excel"); 对于.xls格式
            response.setHeader("Content-Disposition", "attachment; filename=output.xlsx"); // 文件名可以根据需要修改

            try (Workbook workbook = new XSSFWorkbook()) { // 或者使用 HSSFWorkbook for .xls 格式
                for (Map.Entry<String, List<Person>> entry : data.entrySet()) {
                    String sheetName = entry.getKey();
                    List<Person> personList = entry.getValue();

                    Sheet sheet = workbook.createSheet(sheetName);

                    // 创建表头行
                    Row headerRow = sheet.createRow(0);
                    headerRow.createCell(0).setCellValue("Name");
                    headerRow.createCell(1).setCellValue("Age");
                    headerRow.createCell(2).setCellValue("Hometown");
                    headerRow.createCell(3).setCellValue("Hobby Name");
                    headerRow.createCell(4).setCellValue("Hobby Duration");

                    int rowNum = 1;
                    for (Person person : personList) {
                        Row row = sheet.createRow(rowNum++);

                        // 填充 Person 基本信息
                        Cell nameCell = row.createCell(0);
                        nameCell.setCellValue(person.getName());

                        Cell ageCell = row.createCell(1);
                        ageCell.setCellValue(person.getAge());

                        Cell hometownCell = row.createCell(2);
                        hometownCell.setCellValue(person.getHometown());

                        // 填充 Hobby 列表
                        int hobbyColNum = 3;
                        List<Hobby> hobbies = person.getHobbies();
                        for (Hobby hobby : hobbies) {
                            Cell hobbyNameCell = row.createCell(hobbyColNum++);
                            hobbyNameCell.setCellValue(hobby.getName());

                            Cell hobbyDurationCell = row.createCell(hobbyColNum++);
                            hobbyDurationCell.setCellValue(hobby.getDuration());
                        }
                    }
                }
				try (OutputStream out = response.getOutputStream()) {
		            workbook.write(out);
		        } catch (IOException e) {
		            e.printStackTrace();
		        }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        // 创建一个示例的 Map,每个 key 对应一个工作表(sheet)
        // 实际数据应根据业务需求和数据源进行设置
        // 示例中只包含了一个性别和一个 Person,你需要填充实际数据
        Map<String, List<Person>> data = createSampleData();

        // 获取 HttpServletResponse 对象并将数据导出到响应
        HttpServletResponse response = getHttpServletResponse(); // 你需要自行实现获取 HttpServletResponse 对象的方式
        exportToResponse(data, response);
    }

优化思路

代码中,可以看到创建工作簿、设置表头行、设置数据等操作都集中在一起,耦合性较高。如果后面再增加设置样式、设置不同类型单元格的样式,会全部集中到对workbook的操作上,而workbook又在开始时就创建了。

如果将workbook的创建于数据填充进行解耦。并且将创建工作簿、设置表头行、设置数据等操作作为一个公有方法抽取出来,可以供其他导出excel的业务进行使用。形成一个导出excel的公有类。

可以使用建造者模式+策略模式进行设计

代码实现

这里代码通过贴图方式介绍😂😂😂

首先介绍一下包,这里的样式形成一个策略接口,并且有一个默认实现,在strategy包下。然后是templete包,这里是存放具体业务的模板(比如有表头文字、属性映射等等),包含具体样式实现。

然后是一个建造器,用来构建workbook,这也是主要代码。所有代码放到了一个xssf包下,这里用到了excel2007的.xlsx格式的,其实也可以增加excel97的.xls格式。

建造器代码如下:

  1. 首先是workbook,因为在构造方法是需要传入这个workbook,并且是不可变对象,所以设置为final。
  2. 然后是将单元格样式设置为默认样式
  3. 下面就是对不同操作的方法抽取,分别有:创建sheet,设置样式,设置表头、设置数据等,当然,也可以扩展,比如设置列宽,行高这些内容。
  4. 在创建sheet中,使用到了setActiveSheet方法,这个让sheet创建后置为活动,以后就对这个shee进行操作,适合多sheet的表格文件。同时,在后面的操作中也能获取到当前操作的sheet。
  5. 设置data这里,因为不同业务的数据格式、操作是不同的,因此没有通过参数方式直接传入数据,而是提供了函数式接口,让其在调用时能对当前这个sheet进行操作,从而设置数据。同时也可以设置样式。

样式策略接口代码如下:

这里只提供了列头样式和内容样式两个接口,其实可以进行扩展,比如指定sheet样式、行高、列宽等,可以将这些功能都抽取出来,用了修饰最终的workbook。

默认的样式策略实现如下:这里较为简单,就不做过多赘述。

具体使用

使用就比较简单了,只需要创建出建造器,我这里是有不同的sheet,传入了不同的值。然后填充列头,数据即可。

最后通过网络流导出,使用try-resource释放流。

补充

建造者模式

建造者模式是一种创建型设计模式 ,它用于构建复杂对象,将对象的构建步骤解耦并提供更好的控制和可读性。这种模式通常适用于需要创建具有多个可选参数或配置选项的对象,以确保对象构建过程灵活且易于理解。

举例就是springboot的启动的创建,典型的示例是 SpringApplicationBuilder 类,它用于创建 Spring Boot 应用程序的构建器

java 复制代码
public class MySpringBootApp {
    public static void main(String[] args) {
        new SpringApplicationBuilder()
                .sources(MySpringBootApp.class)
                .bannerMode(Banner.Mode.CONSOLE)
                .run(args);
    }
}

这样的创建型设计模式通常和行为型设计模式进行结合使用。

策略模式

策略模式是一种行为设计模式,它允许在运行时选择算法或行为的不同实现。这种模式定义了一组算法,将它们封装成独立的策略对象,并使它们可以互相替换。策略模式有助于使算法的选择独立于使用它们的客户端。

举个例子

Spring Boot 源码中广泛使用了策略模式,尤其在处理各种配置和扩展点时。一个典型的例子是 Spring Boot 的属性处理,其中使用了多种策略来解析配置属性。

Spring Boot 中的属性解析机制是通过 org.springframework.boot.context.properties.ConfigurationProperties 注解来实现的,它支持不同的属性源(如 application.properties、application.yml、环境变量等)和不同的解析策略。

java 复制代码
@ConfigurationProperties("myapp")
public class MyProperties {
    private String property1;
    private int property2;

    // 省略 getter 和 setter

    // 配置属性解析策略
    @ConfigurationPropertiesBinding
    public static class MyPropertiesConverter implements Converter<String, MyProperties> {
        @Override
        public MyProperties convert(String source) {
            // 解析配置属性并返回 MyProperties 对象
            // 这里可以根据不同的解析策略来处理属性的转换
        }
    }
}

在上述示例中,我们使用了 @ConfigurationProperties 注解来声明要处理的属性前缀(myapp),并定义了一个内部的属性解析策略类 MyPropertiesConverter,它实现了 Converter<String, MyProperties> 接口。

Spring Boot 的属性绑定机制将根据不同的属性源(例如 application.properties 文件或环境变量)自动选择相应的属性解析策略(例如 MyPropertiesConverter),并将属性值解析为 MyProperties 对象。

相关推荐
刘某某.7 小时前
使用工厂模式和策略模式实现布隆过滤器
策略模式
Maruko3102 天前
Java 实现excel大批量导出
excel·poi
缘来是庄3 天前
设计模式之建造者模式
java·设计模式·建造者模式
牛奶咖啡134 天前
学习设计模式《十六》——策略模式
学习·设计模式·策略模式·认识策略模式·策略模式的优缺点·何时选用策略模式·策略模式的使用示例
勤奋的知更鸟4 天前
Java 编程之策略模式详解
java·设计模式·策略模式
FreeBuf_4 天前
朝鲜APT组织使用Nim语言恶意软件对macOS发起隐秘Web3与加密货币攻击
macos·web3·策略模式
暮乘白帝过重山4 天前
设计模式篇:灵活多变的策略模式
设计模式·策略模式
GodKeyNet4 天前
设计模式-策略模式
设计模式·策略模式
鼠鼠我呀24 天前
【设计模式06】建造者模式
java·设计模式·建造者模式
守城小轩14 天前
Chromium 136 编译指南 macOS篇:编译优化技巧(六)
macos·策略模式