【SpringBoot+poi实现excel文档导出(三)】(附源码)

SpringBoot+poi实现excel文档导出(三)(附源码)

使用SpringBoot+poi实现excel文档导出,打算分为三篇书写,第一篇基于if-else导出,第二篇提取部分方法作为抽象方法导出,第三篇为全抽象导出。

三、全抽象导出

本篇将用三个模板导出三个不同样式的excel表格。
首先理一下思路 (可以类比一个两头和中间有开口的物体,按照基本的三种颜色的流体往下灌,中间的口不动的情况下,灌红色的流体出红色,灌绿色的流体出绿色;如果上口灌红色的流体,中间灌绿色的流体,出来的颜色就是黄色。把开口的物体作为抽象层的业务代码,流体作为参数,传不同的参数,出不同的结果,但是物体不变)

  1. 将第二章Service层的业务层代码全部抽取出来作为抽象方法,使用工厂生产impl层和不同类型数据处理结果;
  2. 使用“T”“V”“B”三个泛型分别代表实体(业务中暂时用不到,但是使用BaseService查询肯定会用到)、导出表的Vo、查询条件。

1. 接口工厂

import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * 通用Service
 * @param <B> 查询条件泛型
 */
public interface IExportServiceFactory<V, B> {

    /**
     * @Description 通用导出/模板下载
     */
    void exportExcel(B b, HttpServletResponse response) throws Exception;

    /**
     * 通用查询
     * @param b
     * @return
     */
    List<V> findScheduleByConditions(B b);

2. 导出的抽象方法

import com.example.export.util.DataExportUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * 模板/数据导出抽象类
 * @param <T>   实体
 * @param <V>   Vo
 */
public abstract class ExcelDispose<T, V> {

    /**
     * 反射
     * @param valueList
     * @param v
     * @throws IllegalAccessException
     */
    public void resultDispose(List<String> valueList, V v) throws IllegalAccessException {
        // 将实体中的数据提取出来放到list容器中
        Class<?> aClass = v.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        for (int o = 1; o < declaredFields.length; o++) {
            Field declaredField = declaredFields[o];
            declaredField.setAccessible(true);
            Object value = declaredField.get(v);
            String s = null != value ? value.toString() : "";
            valueList.add(s);
            // 关闭除public外的访问权限
            declaredField.setAccessible(false);
        }
    }

    /**
     * 导出主逻辑
     * @param path excel文件路径
     * @param list 查询出来的数据
     * @param cellNameList 表头
     * @param i 对应文件的新行索引
     * @param j 对应文件的表头索引
     * @param response
     * @param width 列宽
     * @throws Exception
     */
    public void excelPathDispose(String path, List<T> list, List<String> cellNameList,
                                 int i, int j, HttpServletResponse response,
                                 Integer width, IDispose<T, V> dispose) throws Exception {
        InputStream inputStream = DataExportUtils.getStream(path);
        XSSFWorkbook wb = DataExportUtils.getwb(inputStream);
        SXSSFWorkbook swb = DataExportUtils.getswb(wb);
        Sheet sheet =  DataExportUtils.getSheet(wb, 0);
        Row row = DataExportUtils.getRow(sheet, j);
        CellStyle cellStyle = DataExportUtils.getCellStyle(swb);
        int cells = row.getPhysicalNumberOfCells();
        for (Cell cell : row) {
            String stringCellValue = cell.getStringCellValue();
            cellNameList.add(stringCellValue);
        }
        dataDispose(list, cellNameList, i, width, dispose, sheet, cellStyle, cells);
        DataExportUtils.sxssfWriteAndClose(response, inputStream, wb, swb);
    }

    /**
     * 对数据进行处理
     * @param list
     * @param cellNameList
     * @param i
     * @param width
     * @param dispose
     * @param sheet
     * @param cellStyle
     * @param cells
     * @throws IllegalAccessException
     */
    private void dataDispose(List<T> list, List<String> cellNameList, int i, Integer width, IDispose<T, V> dispose, Sheet sheet, CellStyle cellStyle, int cells) throws IllegalAccessException {
        Row row;
        for (int k = 0; k < list.size(); k++) {
            List<String> valueList = new ArrayList<>();
            // 创建新行
            V v = dispose.getType(list, k);
            resultDispose(valueList, v);
            row = sheet.createRow(i++);
            int xh = k + 1;
            valueList.add(0, Integer.toString(xh));
            // 做一些数据上的处理
            valueListDispose(valueList, v);
            dispose.dataDispose(row, sheet, cellNameList,valueList, cellStyle, width, cells);
        }
    }

    /**
     * 子类必须重写,比如对应字段的编码翻译成文字
     * @param valueList
     * @param v
     */
    public abstract void valueListDispose(List<String> valueList, V v);
}

3. 实现类

3.1. 实现类1(用户)
import com.example.export.dispose.ExcelDispose;
import com.example.export.dispose.IDispose;
import com.example.export.dispose.datadispose.UserExport;
import com.example.export.service.IExportServiceFactory;
import com.example.export.vo.UserVo;
import com.example.export.vo.ScheduleVo;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

@Service
public class UserExportServiceImpl implements IExportServiceFactory<UserVo, ScheduleVo> {
    @Override
    public void exportExcel(ScheduleVo vo, HttpServletResponse response) throws Exception {
        // 新行的索引
        int i = 1;
        // 表头索引
        int j = 0;
        List<String> cellNameList = new ArrayList<>();
        Integer width = null;
        IDispose<UserVo, UserVo> dispose = new UserExport();
        ExcelDispose<UserVo, UserVo> zhqJtsyjcExcelDispose = new UserExport();
//        vo.setYljgLb(DicYljgUtils.findByOrganId(UserUtils.getUser(vo.getUserId()).getOrganId()).getYljgLb());
//        导出excel模板根据传入的参数置空list,1:模板导出;2:全量导出
//        List<UserVo> users = vo.getMb().equals("1") ? new ArrayList<>() : query(vo);
        List<UserVo> scheduleByConditions = findScheduleByConditions(vo);
        String path = "excel/user.xlsx";
        zhqJtsyjcExcelDispose.excelPathDispose(path, scheduleByConditions, cellNameList, i, j, response, width, dispose);
    }

    /**
     * 假设这里是一个查询语句,得到查询结果
     * @param vo
     * @return
     */
    public List<UserVo> findScheduleByConditions(ScheduleVo vo) {
        UserVo userVo1 = new UserVo();
        UserVo userVo2 = new UserVo();
        UserVo userVo3 = new UserVo();
        UserVo userVo4 = new UserVo();
        UserVo userVo5 = new UserVo();
        List<UserVo> userVos = new ArrayList<>();
        userVo1.setName("账伞").setAge("17").setSex("男").setAddress("北京市朝阳区上雕刻技法").setContactInformation("2342893472374");
        userVo2.setName("里斯").setAge("43").setSex("女").setAddress("上海市黄浦区的发射点").setContactInformation("34534453");
        userVo3.setName("汪芜").setAge("23").setSex("男").setAddress("陕西省西安市瓦基尔克").setContactInformation("3131231");
        userVo4.setName("马尔扎哈").setAge("534").setSex("男").setAddress("山西省太原市昆仑山地方").setContactInformation("23544343");
        userVo5.setName("古力娜扎").setAge("43").setSex("女").setAddress("广东省广州市的快速减肥").setContactInformation("1213124242");
        userVos.add(userVo1);
        userVos.add(userVo2);
        userVos.add(userVo3);
        userVos.add(userVo4);
        userVos.add(userVo5);
        return userVos;
    }

}
3.2. 实现类2(汽车)
import com.example.export.dispose.ExcelDispose;
import com.example.export.dispose.IDispose;
import com.example.export.dispose.datadispose.CarExport;
import com.example.export.service.IExportServiceFactory;
import com.example.export.vo.CarVo;
import com.example.export.vo.ScheduleVo;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

@Service
public class CarExportServiceImpl implements IExportServiceFactory<CarVo, ScheduleVo> {

    @Override
    public void exportExcel(ScheduleVo vo, HttpServletResponse response) throws Exception {
        // 新行的索引
        int i = 1;
        // 表头索引
        int j = 0;
        List<String> cellNameList = new ArrayList<>();
        Integer width = null;
        IDispose<CarVo, CarVo> dispose = new CarExport();
        ExcelDispose<CarVo, CarVo> zhqJtsyjcExcelDispose = new CarExport();
//        vo.setYljgLb(DicYljgUtils.findByOrganId(UserUtils.getUser(vo.getUserId()).getOrganId()).getYljgLb());
//        导出excel模板根据传入的参数置空list,1:模板导出;2:全量导出
//        List<UserVo> users = vo.getMb().equals("1") ? new ArrayList<>() : query(vo);
        List<CarVo> scheduleByConditions = findScheduleByConditions(vo);
        String path = "excel/car.xlsx";
        zhqJtsyjcExcelDispose.excelPathDispose(path, scheduleByConditions, cellNameList, i, j, response, width, dispose);
    }

    @Override
    public List<CarVo> findScheduleByConditions(ScheduleVo vo) {
        CarVo carVo1 = new CarVo();
        CarVo carVo2 = new CarVo();
        CarVo carVo3 = new CarVo();
        CarVo carVo4 = new CarVo();
        CarVo carVo5 = new CarVo();
        CarVo carVo6 = new CarVo();
        CarVo carVo7 = new CarVo();
        List<CarVo> carVos = new ArrayList<>();
        carVo1.setBrand("奥迪").setColor("红色").setLength("6.2").setWidth("2.4").setKilometre("600公里").setSpeed("150km/h").setLifetime("3年");
        carVo2.setBrand("宝马").setColor("蓝色").setLength("6.3").setWidth("2.5").setKilometre("700公里").setSpeed("160km/h").setLifetime("4年");
        carVo3.setBrand("比亚迪").setColor("黑色").setLength("6.4").setWidth("2.6").setKilometre("800公里").setSpeed("170km/h").setLifetime("5年");
        carVo4.setBrand("长安").setColor("橙色").setLength("6.5").setWidth("2.7").setKilometre("900公里").setSpeed("180km/h").setLifetime("6年");
        carVo5.setBrand("长城").setColor("渐变红").setLength("6.6").setWidth("2.8").setKilometre("1000公里").setSpeed("190km/h").setLifetime("7年");
        carVo6.setBrand("五菱之光").setColor("青色").setLength("6.7").setWidth("2.9").setKilometre("1100公里").setSpeed("200km/h").setLifetime("8年");
        carVo7.setBrand("奥托").setColor("玫瑰红").setLength("6.8").setWidth("2.0").setKilometre("11200公里").setSpeed("140km/h").setLifetime("9年");
        carVos.add(carVo1);
        carVos.add(carVo2);
        carVos.add(carVo3);
        carVos.add(carVo4);
        carVos.add(carVo5);
        carVos.add(carVo6);
        carVos.add(carVo7);
        return carVos;
    }
}
3.3. 实现类3(公司)
import com.example.export.dispose.ExcelDispose;
import com.example.export.dispose.IDispose;
import com.example.export.dispose.datadispose.CompanyExport;
import com.example.export.service.IExportServiceFactory;
import com.example.export.vo.CompanyVo;
import com.example.export.vo.ScheduleVo;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

@Service
public class CompanyExportServiceImpl implements IExportServiceFactory<CompanyVo, ScheduleVo> {

    @Override
    public void exportExcel(ScheduleVo vo, HttpServletResponse response) throws Exception {
        // 新行的索引
        int i = 2;
        // 表头索引
        int j = 1;
        List<String> cellNameList = new ArrayList<>();
        Integer width = null;
        IDispose<CompanyVo, CompanyVo> dispose = new CompanyExport();
        ExcelDispose<CompanyVo, CompanyVo> zhqJtsyjcExcelDispose = new CompanyExport();
//        vo.setYljgLb(DicYljgUtils.findByOrganId(UserUtils.getUser(vo.getUserId()).getOrganId()).getYljgLb());
//        导出excel模板根据传入的参数置空list,1:模板导出;2:全量导出
//        List<UserVo> users = vo.getMb().equals("1") ? new ArrayList<>() : query(vo);
        List<CompanyVo> scheduleByConditions = findScheduleByConditions(vo);
        String path = "excel/company.xlsx";
        zhqJtsyjcExcelDispose.excelPathDispose(path, scheduleByConditions, cellNameList, i, j, response, width, dispose);
    }

    @Override
    public List<CompanyVo> findScheduleByConditions(ScheduleVo vo) {
        CompanyVo companyVo1 = new CompanyVo();
        CompanyVo companyVo2 = new CompanyVo();
        CompanyVo companyVo3 = new CompanyVo();
        CompanyVo companyVo4 = new CompanyVo();
        List<CompanyVo> companyVos = new ArrayList<>();
        companyVo1.setName("北京市律师事务所").setAddress("北京市朝阳区觉得还是开发").setPeopleNum("59").setAverageSalary("12300元").setBusiness("打官司").setScale("200平");
        companyVo2.setName("上海市美食加工厂").setAddress("上海市浦东新区登记是否").setPeopleNum("519").setAverageSalary("12400元").setBusiness("做食品").setScale("2000平");
        companyVo3.setName("上海市机械加工厂").setAddress("上海市闵行区健身房的和").setPeopleNum("5119").setAverageSalary("12500元").setBusiness("加工零件").setScale("20000平");
        companyVo4.setName("陕西旅游公司").setAddress("陕西省西安市扣税的风格").setPeopleNum("58").setAverageSalary("12600元").setBusiness("旅游推荐").setScale("200000平");
        companyVos.add(companyVo1);
        companyVos.add(companyVo2);
        companyVos.add(companyVo3);
        companyVos.add(companyVo4);
        return companyVos;
    }
}

4. 抽象数据处理

import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;

import java.util.List;

/**
 * 抽象数据处理
 * @param <T> 实体泛型
 */
public interface IDispose<T, V> {

    /**
     * 获取索引K下的的对象
     * @param list
     * @param k
     * @return
     */
    V getType(List<T> list, int k);

    /**
     * 对表数据处理并写入到单元格,每张表必须实现
     * @param row
     * @param sheet
     * @param cellNameList
     * @param valueList
     * @param cellStyle
     * @param width
     * @param cells
     */
    void dataDispose(Row row, Sheet sheet, List<String> cellNameList,
                            List<String> valueList, CellStyle cellStyle, Integer width, int cells);
4.1. 数据处理实现1(用户,全样式)
import com.example.export.dispose.ExcelDispose;
import com.example.export.dispose.IDispose;
import com.example.export.util.DataExportUtils;
import com.example.export.vo.UserVo;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;

import java.util.List;

/**
 * 军团菌水环境样本监测管理导出实例
 * @author wp
 */
public class UserExport extends ExcelDispose<UserVo, UserVo> implements IDispose<UserVo, UserVo> {

    @Override
    public void dataDispose(Row row, Sheet sheet, List<String> cellNameList,
                            List<String> valueList, CellStyle cellStyle, Integer width, int cells) {
        for (int j = 0; j < cells; j++) {
            Cell cell = row.createCell(j);
            for (int z = 0; z < valueList.size(); z++) {
                if (j == z) {
                    if (j == 0) {
                        // 插入序号,并按照表头对序号进行列宽设置
                        width = DataExportUtils.checkNum(cellNameList.get(0).length());
                        sheet.setColumnWidth(j, width);
                        cell.setCellValue(valueList.get(z));
                        cell.setCellStyle(cellStyle);
                        break;
                    }
                    cell.setCellValue(valueList.get(z));
                    cell.setCellStyle(cellStyle);
                    break;
                }
            }
        }
    }

    @Override
    public UserVo getType(List<UserVo> list, int k) {
        // 对特定数据处理方法
        return list.get(k);
    }

    @Override
    public void valueListDispose(List<String> valueList, UserVo userVo) {
//        例如:valueList.set(2, 调用翻译方法翻译字典项);
    }
}

4.2. 数据处理实现2(汽车,去掉所有样式)
import com.example.export.dispose.ExcelDispose;
import com.example.export.dispose.IDispose;
import com.example.export.util.DataExportUtils;
import com.example.export.vo.CarVo;
import com.example.export.vo.UserVo;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;

import java.util.List;

/**
 * 军团菌水环境样本监测管理导出实例
 * @author wp
 */
public class CarExport extends ExcelDispose<CarVo, CarVo> implements IDispose<CarVo, CarVo> {

    @Override
    public void dataDispose(Row row, Sheet sheet, List<String> cellNameList,
                            List<String> valueList, CellStyle cellStyle, Integer width, int cells) {
        for (int j = 0; j < cells; j++) {
            Cell cell = row.createCell(j);
            for (int z = 0; z < valueList.size(); z++) {
                if (j == z) {
                    if (j == 0) {
                        // 插入序号,并按照表头对序号进行列宽设置
                        // 删除样式和列宽设置
//                        width = DataExportUtils.checkNum(cellNameList.get(0).length());
//                        sheet.setColumnWidth(j, width);
                        cell.setCellValue(valueList.get(z));
//                        cell.setCellStyle(cellStyle);
                        break;
                    }
                    cell.setCellValue(valueList.get(z));
//                    cell.setCellStyle(cellStyle);
                    break;
                }
            }
        }
    }

    @Override
    public CarVo getType(List<CarVo> list, int k) {
        // 对特定数据处理方法
        return list.get(k);
    }

    @Override
    public void valueListDispose(List<String> valueList, CarVo carVo) {
//        例如:valueList.set(2, 调用翻译方法翻译字典项);
//       给车长和车宽都加上单位
        valueList.set(3, valueList.get(3) + "米");
        valueList.set(4, valueList.get(4) + "米");
    }
}
4.3. 数据处理实现3(公司, 去掉样式,保留动态列宽设置)
import com.example.export.dispose.ExcelDispose;
import com.example.export.dispose.IDispose;
import com.example.export.util.DataExportUtils;
import com.example.export.vo.CompanyVo;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;

import java.util.List;

/**
 * 军团菌水环境样本监测管理导出实例
 * @author wp
 */
public class CompanyExport extends ExcelDispose<CompanyVo, CompanyVo> implements IDispose<CompanyVo, CompanyVo> {

    @Override
    public void dataDispose(Row row, Sheet sheet, List<String> cellNameList,
                            List<String> valueList, CellStyle cellStyle, Integer width, int cells) {
        for (int j = 0; j < cells; j++) {
            Cell cell = row.createCell(j);
            for (int z = 0; z < valueList.size(); z++) {
                if (j == z) {
                    if (j == 0) {
                        // 插入序号,并按照表头对序号进行列宽设置
                        // 删除样式但不删除格式
                        width = DataExportUtils.checkNum(cellNameList.get(0).length());
                        sheet.setColumnWidth(j, width);
                        cell.setCellValue(valueList.get(z));
//                        cell.setCellStyle(cellStyle);
                        break;
                    }
                    cell.setCellValue(valueList.get(z));
//                    cell.setCellStyle(cellStyle);
                    break;
                }
            }
        }
    }

    @Override
    public CompanyVo getType(List<CompanyVo> list, int k) {
        // 对特定数据处理方法
        return list.get(k);
    }

    @Override
    public void valueListDispose(List<String> valueList, CompanyVo companyVo) {
//        例如:valueList.set(2, 调用翻译方法翻译字典项);
    }
}

5. 实体Vo

5.1. 用户
import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
public class UserVo {

    private String id;
    private String name;
    private String age;
    private String sex;
    private String address;
    private String contactInformation;
}
5.2. 汽车
import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
public class CarVo {

    private String id;
    private String brand;
    private String color;
    private String length;
    private String width;
    private String kilometre;
    private String speed;
    private String lifetime;
}
5.3. 公司
import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
public class CompanyVo {

    private String id;
    private String name;
    private String address;
    private String peopleNum;
    private String scale;
    private String averageSalary;
    private String business;
}

6. 表格模板

6.1. 用户模板

在这里插入图片描述

6.2. 汽车模板

在这里插入图片描述

6.3. 公司模板

在这里插入图片描述

7. Controller层(其他两层参考如下用户层)

import com.example.export.service.IExportServiceFactory;
import com.example.export.vo.ScheduleVo;
import com.example.export.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private IExportServiceFactory<UserVo, ScheduleVo> exportService;

    @GetMapping("/export")
    public void export(ScheduleVo scheduleVo, HttpServletResponse response) throws Exception {
        exportService.exportExcel(scheduleVo, response);
    }
}

8. 输出结果(注意:postman导出需要更改后缀:zip->xlsx)

8.1. 用户保留所有样式

在这里插入图片描述

8.2. 汽车删除所有样式

在这里插入图片描述

8.3. 公司除自适应列宽外样式全部删除

在这里插入图片描述

9. 项目层级

在这里插入图片描述
本章内容解决了项目内繁琐的if-else开发模式,并且抽取抽象方法,使用工厂模式自动生成对象,简单的静态代理模式增强代码块,强化各个类型的私有属性,这样就可以自定义一个通用的导出方法,无论业务怎么变,抽象方法自身不会发生改变,如果有需求需要强制改变所有类型的结构,我们只需要将抽象方法继承过来,使用简单的代理就可以达到要求,不会动原有的代码,符合设计模式的开闭原则,并且代码的灵动性非常高。
如果有新增其他类型的导出,我们只需要继承抽象类,实现抽象数据处理工厂的方法,就可以达到导出功能。
纯手打,技术有限,请各位大佬批评指正,谢谢!
项目已放在git上。
导出项目git地址:
https://gitee.com/table-tennis-king/export_test.git

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值