定制软件Java真的不难(五十一)SpringBoot使用EasyExcel实现导出

定制软件大家好久不见!

一、什么是EasyExcel?

EasyExcel定制软件是一个基于Java的简单、定制软件省内存的读写Excel定制软件的开源项目。定制软件在尽可能节约内存的情定制软件况下支持读写百M的Excel。
github地址: https://github.com/alibaba/easyexcel
定制软件官方文档地址https://www.yuque.com/easyexcel/doc/easyexcel

定制软件当然还有一个POI定制软件也可以实现操作Excel,Apache POI提供API给Java程序对Microsoft Office定制软件格式档案读和写的功能,POI为“Poor Obfuscation Implementation”定制软件的首字母缩写,意为“定制软件简洁版的模糊实现”

EasyExcel和POI的区别:


二、EasyExcel定制软件的实际使用

定制软件首先导入依赖:

<dependency>    <groupId>com.alibaba</groupId>    <artifactId>easyexcel</artifactId>    <version>2.2.4</version></dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

依赖版本按需使用即可,一些基本的操作大家看官方文档即可,在这里就记录一下自己通过EasyExcel导出的表格及过程

首先看一下需要导出的模板:


区域说明:
A:单个单元格填充
B:列表填充
C:列表填充(但单元格格式与B区域不同)
D:单个单元格填充

一、A区域的填充数据模板的设置:

这个区域填充还是很简单的,只要给每个表格取个参数名,用{}包裹,Java里面用Map来填充即可。Map的键对应{}里面的参数名,对应的值就是填充进去的值:

例如这样,以下数据都是从数据库查出后填入Map即可:

 HashMap<String, Object> workOrderFileData = new HashMap<>();        for (ProjectWorkOrderFileData p : WorkOrderFileList) {            workOrderFileData.put("projectCode", p.getProjectCode());            workOrderFileData.put("projectName", p.getProjectName());            workOrderFileData.put("inspectedEnt", p.getInspectedEnt());            workOrderFileData.put("customerAddress", p.getCustomerAddress());            workOrderFileData.put("linkMan", p.getLinkMan());            workOrderFileData.put("linkPhone", p.getLinkPhone());            workOrderFileData.put("bizCreateTime", p.getBizCreateTime().substring(0, 10));            workOrderFileData.put("customerName", p.getCustomerName());            workOrderFileData.put("prodCompany", p.getProdCompany());            workOrderFileData.put("testCode", p.getTestCode());            workOrderFileData.put("batchCode", p.getBatchCode());            workOrderFileData.put("region", region); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

二、B和C区域的填充数据模板的设置:

因为B区域是有两个列表,所以我们一定在模板内区分开来,给每个列表取个参数名,然后给每个字段取个参数名,通过列表参数名点(.)字段参数名即可:
即:{} 代表普通变量, {.} 代表是list的变量 {前缀.} 前缀可以区分不同的list
注意: 用{} 来表示你要用的变量 如果本来就有"{“,”}" 特殊字符 用"{“,”}"代替

对于这两组数据,Java里面使用两个列表储存即可,列表内可以存一个对象:

ArrayList<SampleData> SampleDataList = service.selectSampleData(proId);ArrayList<AnalysisMethodData> analysisMethodDataList = service.selectAnalysisMethodData(proId);
  • 1
  • 2

对象里面的字段名即是该列表所有字段名:

@NoArgsConstructor@AllArgsConstructor@Data@Builderpublic class SampleData {    private int number;    private String typeName;    private String redFolderName;    private String redAnalyzeItems;    private int spotFrequency;    private int frequency;    private int day;    private int cycleOrder;    private int timesOrder;    private int sampleOrder;    private String remarks;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

D区域的填充和A区域是一样的,通过Map来填充即可,因为是一对一的关系


三、两个列表之间单元格样式不一样的解决办法

通过模板可以看到BC两个列表之前的单元格样式不一样,如果不做处理,在填充的时候,C区域的样式会根据B区域的样式来填充,也就是C区域合并的单元格会被拆分,所以需要一个工具类:

public class MyHandler extends AbstractMergeStrategy {    @Override    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {        if (relativeRowIndex == null || relativeRowIndex == 0) {            return;        }        int rowIndex = cell.getRowIndex();        int colIndex = cell.getColumnIndex();        sheet = cell.getSheet();        Row preRow = sheet.getRow(rowIndex - 1);        Cell preCell = preRow.getCell(colIndex);//获取上一行的该格        List<CellRangeAddress> list = sheet.getMergedRegions();        CellStyle cs = cell.getCellStyle();        cell.setCellStyle(cs);        for (CellRangeAddress cellRangeAddress : list) {            if (cellRangeAddress.containsRow(preCell.getRowIndex()) && cellRangeAddress.containsColumn(preCell.getColumnIndex())) {                int lastColIndex = cellRangeAddress.getLastColumn();                int firstColIndex = cellRangeAddress.getFirstColumn();                CellRangeAddress cra = new CellRangeAddress(cell.getRowIndex(), cell.getRowIndex(), firstColIndex, lastColIndex);                sheet.addMergedRegion(cra);                RegionUtil.setBorderBottom(BorderStyle.THIN, cra, sheet);                RegionUtil.setBorderLeft(BorderStyle.THIN, cra, sheet);                RegionUtil.setBorderRight(BorderStyle.THIN, cra, sheet);                RegionUtil.setBorderTop(BorderStyle.THIN, cra, sheet);                return;            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

直接复制当工具类就完事!


三、完成其他配置,开始填充

我们还要设置两个地址:模板的位置以及导出后文件的储存位置,以下是控制层完整代码

@GetMapping(path = "/generateProjectWorkOrder")    public JsonResp<String> generateProjectWorkOrder(@RequestParam("proId") String proId) {        //设置模板位置以及导出后储存位置        String templateFile = "D:/WorkProject/ExcelTemplate/模板.xls";        String resultFile = "D:/WorkProject/ExcelTemplate/WorkOrderFile/" +"导出结果.xls";        FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();        ExcelWriter excelWriter = EasyExcel.write(resultFile).withTemplate(templateFile).build();        //使用让该组单元格格式不受影响的工具类        WriteSheet sheet = EasyExcel.writerSheet(0).registerWriteHandler(new MyHandler()).build();        //获取数据(分别是ABCD四组数据)        HashMap<String, Object> workOrderFileData = service.selectWorkOrder(proId);        ArrayList<SampleData> SampleDataList = service.selectSampleData(proId);        ArrayList<AnalysisMethodData> analysisMethodDataList = service.selectAnalysisMethodData(proId);        HashMap<String, String> reviewerData = service.selectReviewerData(proId);        //单组填充(A区域)        excelWriter.fill(workOrderFileData, sheet);        //多个列表填充(B、C区域)        // 如果有多个list 模板上必须有{前缀.} 这里的前缀就是 data1,然后多个list必须用 FillWrapper包裹        excelWriter.fill(new FillWrapper("data1", SampleDataList), fillConfig, sheet);        excelWriter.fill(new FillWrapper("data2", analysisMethodDataList), fillConfig, sheet);        //单组填充(D区域)        excelWriter.fill(reviewerData, sheet);        //关闭流        excelWriter.finish();        //返回数据        JsonResp<String> objectJsonResp = new JsonResp<>();        //返回路径        resultFile = "lims/downloadGenerateExcel?path=" + resultFile;        objectJsonResp.setData(resultFile);        return objectJsonResp;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

数据获取的方式按照自己的格式来即可,若完成以上编写,可以实现本地的导出与下载,若需要部署在服务器上,则还需要从服务器下载到本地


三、服务器项目导出后下载到本地

若把项目部署在服务器上,使用该功能首先是下载到服务器上,然后再从服务器上下载到本地电脑。
我们可以使用HttpServletResponse response 来操作:
代码如下:

    @GetMapping(path = "/downloadGenerateExcel")    public void download(String path, HttpServletResponse response) {        try {            // path是指想要下载的文件的路径            File file = new File(path);            String filename = file.getName();            // 将文件写入输入流            FileInputStream fileInputStream = new FileInputStream(file);            InputStream fis = new BufferedInputStream(fileInputStream);            byte[] buffer = new byte[fis.available()];            //noinspection ResultOfMethodCallIgnored            fis.read(buffer);            fis.close();            response.reset();            response.setCharacterEncoding("UTF-8");            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));            // 告知浏览器文件的大小            response.addHeader("Content-Length", "" + file.length());            OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());            response.setContentType("application/octet-stream");            outputStream.write(buffer);            outputStream.flush();        } catch (IOException ex) {            ex.printStackTrace();        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

这个方法的参数就是上述方法最后的代码:

//返回数据JsonResp<String> objectJsonResp = new JsonResp<>();//返回路径resultFile = "lims/downloadGenerateExcel?path=" + resultFile;objectJsonResp.setData(resultFile);return objectJsonResp;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

也就是导出完成后返回的参数可以自动调用这个方法,把返回的参数自动传入该方法的Path,即可完成从服务器下载到本地。


四、使用效果

运行对应的接口,即可把数据导出并填充在指定的Excel模板内,并下载到指定位置,使用以上模板导出的结果如下:

以上均为模拟数据,大家根据实际情况来编写即可

在最后附上EasyExcel最新的文档地址https://easyexcel.opensource.alibaba.com/docs/current/quickstart/fill


网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发