EasyExcel复杂模板导出

EasyExcel复杂模板导出

1.引入依赖

  <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>easyexcel</artifactId>
         <version>3.0.2</version>
         <scope>compile</scope>
  </dependency>
注意事项:当项目中使用过poi时,引入easyexcel需要将easyexcel中的poi进行排除,否则会出现版本冲突,如下:
           <exclusions>
                <exclusion>
                    <groupId>javax.servlet</groupId>
                    <artifactId>servlet-api</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.apache.poi</groupId>
                    <artifactId>poi</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.apache.poi</groupId>
                    <artifactId>poi-ooxml</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.apache.poi</groupId>
                    <artifactId>poi-ooxml-schemas</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>cglib</groupId>
                    <artifactId>cglib</artifactId>
                </exclusion>
            </exclusions>

2.定义导出模板

1.普通数据定义:直接使用下图所示格式进行模板定义即可

在这里插入图片描述

2.列表数据定义:直接使用下图所示格式进行模板定义即可

在这里插入图片描述

4.封装导入数据

1.普通数据封装:使用Map对应模板的普通数据字段进行数据封装即可

  Map<String, Object> map = new HashMap<>();
  map.put("settleCost", settleCost);
  map.put("settleNum", settleNum);

2.列表数据封装:使用List封装Map数据即可

ArrayList<Map<String, Object>> list = new ArrayList<>();
HashMap<String, Object> hashMap = new HashMap<>();

hashMap.put("engineeringName", balance.getEngineeringName());
hashMap.put("ProductName", balance.getProductName());
hashMap.put("faceValue", balance.getFaceValue());

list.add(hashMap);

4.导入的整体结构

            InputStream is = null;
            // 取出模板
            try {
                //服务器
                is = ResourceUtil.getStream(evn.getProperty("concretePath"));
                //本地
                is = ResourceUtil.getStream("classpath:template/混凝土协作结算单.xls");

                //导入数据
                ExcelWriter excelWriter = getExcelWriter(response, list1, list2, map, is);

                excelWriter.finish();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

5.获取定义的模板

1.获取本地模板:方便测试

1.1在启动类的resources下存入模板文件
1.2在pom文件中加入以下代码,保证在打包代码时不会将模板文件进行打包
          <resources>
			
			<resource>
				<directory>src/main/resourcesdirectory>
				<targetPath>${project.build.directory}/classestargetPath>
				<includes>
					<include>**/*include>
				includes>
				<filtering>truefiltering>
				<excludes>
					<exclude>**/*.xlsxexclude>
					<exclude>**/*.xlsexclude>
				excludes>
			resource>
			<resource>
				<directory>src/main/resourcesdirectory>
				<filtering>falsefiltering>
				<includes>
					<include>**/*.xlsxinclude>
					<include>**/*.xlsinclude>
				includes>
			resource>
		
1.3使用工具类ResourceUtil获取模板文件流
is = ResourceUtil.getStream("classpath:template/混凝土协作结算单.xls");

2.获取服务器模板:业务使用

2.1在配置文件中配置指定模板路径,并将模板放到服务器对应的位置
concretePath: /usr/exportTemplate/concreteTemplate/混凝土协作结算单.xls   
2.2使用JAVA8提供的工具类ResourceUtil获取模板文件流
is = ResourceUtil.getStream(evn.getProperty("concretePath"));

6.封装的数据导入模板并导出

        List<CellRangeAddress> list = new ArrayList<>();
        //new CellRangeAddress(开始行,结束行,开始列,结束列)
        list.add(new CellRangeAddress(25, 25, 0, 2));

        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
        String fileName = "混凝土协作结算单-" + format.format(new Date()) + ".xls";
        ExcelWriter excelWriter = EasyExcel.write(TemplateExcelUtils.
        getOutputStream(fileName, response)).withTemplate(is).excelType(ExcelTypeEnum.XLS).build();
        WriteSheet writeSheet = EasyExcel.writerSheet().registerWriteHandler(new MyHandler(0, list)).build();
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        excelWriter.fill(new FillWrapper("list1", list1), fillConfig, writeSheet);
        excelWriter.fill(map, writeSheet);

        WriteSheet writeSheet1 = EasyExcel.writerSheet(1).build();
        excelWriter.fill(new FillWrapper("list2", list2), fillConfig, writeSheet1);
        excelWriter.fill(map, writeSheet1);
        return excelWriter;

1.设置导出流的文件编码

package com.hxls.icps.system.service.util;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;

/**
 * @version 1.0
 * @date 2022-12-11 18:00
 */
public class TemplateExcelUtils {

    public static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
        try {
            //服务器
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", new String(fileName.getBytes("UTF-8"),"iso-8859-1"));
            //本地
//            fileName = URLEncoder.encode(fileName, "UTF-8");
//            response.setContentType("application/vnd.ms-excel");
//            response.setCharacterEncoding("utf-8");
//            response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
//            response.setHeader("Pragma", "public");
//            response.setHeader("Cache-Control", "no-store");
//            response.addHeader("Cache-Control", "max-age=0");
            return response.getOutputStream();
        } catch (IOException e) {
            throw new Exception("导出excel表格失败!", e);
        }
    }
}


2.合并单元格

合并单元格设置
CellRangeAddress对象用于存放合并单元格的开始行,结束行,开始列,结束列

 List<CellRangeAddress> list = new ArrayList<>();
 //new CellRangeAddress(开始行,结束行,开始列,结束列)
 ist.add(new CellRangeAddress(25, 25, 0, 2));
合并单元格类
package com.hxls.icps.system.service.util;
 
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;
import java.util.List;
 
/**
 * 合并单元格处理类
 */
public class MyHandler extends AbstractMergeStrategy {
 
    /**
     * 合并开始行
     */
    private Integer startRow = 0;
    /**
     * list表格所有的合并列集合
     */
    private List<CellRangeAddress> cellRangeAddressList = null;
 
    public MyHandler() {
    }
 
    public MyHandler(int startRow, List<CellRangeAddress> cellRangeAddressList) {
        this.startRow = startRow;
        this.cellRangeAddressList = cellRangeAddressList;
    }
 
    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
        // 设置样式
        CellStyle cellStyle = cell.getCellStyle();
        //水平居中
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        //自动换行
        cellStyle.setWrapText(true);
        //在这里判断从哪一行开始调用合并的方法
        if (cell.getRowIndex() > this.startRow) {
            if (relativeRowIndex == null || relativeRowIndex == 0) {
                return;
            }
            mergeColumn(sheet, cell, head, relativeRowIndex);
        }
    }
 
    /**
     * 合并单元格
     *
     * @param sheet
     * @param cell
     * @param head
     * @param relativeRowIndex
     */
    protected void mergeColumn(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
        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 = this.cellRangeAddressList;
        for (int i = 0; i < list.size(); i++) {
            CellRangeAddress cellRangeAddress = list.get(i);
            if (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;
            }
        }
    }
}

3.列表数据自动换行:此配置可以让列表数据再导入数据时自动进行换行

FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();

注意事项

1.模板最好使用XLS文件进行定义,XLSX不支持,且在导入数据时,需要指定文件类型为XLS文件
2.导入的数据如果有列表数据,需要先进行列表数据的导入,再进行普通数据的导入,否则会使先导入的普通数据消失

你可能感兴趣的:(java,开发语言)