【Java】将数据导入到指定Excel模板(多个sheet页)当中(代码实现)

Mxin5 2024-09-10 17:05:02 阅读 87

目录

1.引入依赖

2.工具类

ExcelUtils:

ExcelFillCellMergeStrategyUtils:

ExcelFillCellMergePrevColUtils:

3.上传Excel模板文件

4.接口Controller测试

实体类User

接口ExcelController

Postman进行接口测试:

excel文件验证


        实际开发过程中,经常会遇到这种业务,第一种方式就是后台直接生成一个带有数据的excel文件,第二种就是提前编写好Excel模板文件,直接将数据填充到Excel文件当中。那么下述就分享一下这个功能代码如何实现。

1.引入依赖

<code> <dependency>

<groupId>com.alibaba</groupId>

<artifactId>easyexcel</artifactId>

<version>2.2.7</version>

</dependency>

<!--实现数据导出到excel模板当中-->

<dependency>

<groupId>org.apache.poi</groupId>

<artifactId>poi</artifactId>

<version>4.1.2</version>

</dependency>

<dependency>

<groupId>org.apache.poi</groupId>

<artifactId>poi-ooxml</artifactId>

<version>4.1.2</version>

<!--版本用最新的-->

</dependency>

2.工具类

ExcelUtils:

package com.slice.reactminiospring.mapper;

import com.alibaba.excel.EasyExcel;

import com.alibaba.excel.ExcelWriter;

import com.alibaba.excel.write.metadata.WriteSheet;

import com.alibaba.excel.write.metadata.fill.FillConfig;

import com.alibaba.excel.write.metadata.fill.FillWrapper;

import com.slice.reactminiospring.util.ExcelFillCellMergePrevColUtils;

import com.slice.reactminiospring.util.ExcelFillCellMergeStrategyUtils;

import jakarta.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;

import org.springframework.core.io.ClassPathResource;

import java.io.IOException;

import java.io.InputStream;

import java.net.URLEncoder;

import java.time.LocalDate;

import java.time.ZoneId;

import java.time.format.DateTimeFormatter;

import java.util.*;

/**

* excel导出工具类

*/

public class ExcelUtils {

/**

* 传递多个sheet页

* <p>

* // 创建额外的Sheet页的数据

* List<List<Map<String, Object>>> additionalSheetsData = new ArrayList<>();

* additionalSheetsData.add(innerMapList);

* additionalSheetsData.add(innerMapList);

* <p>

* ExcelExportUtils.exportToTemplateWithMultipleSheets(response, "excel/excel模板1.xls", "excel模板1",

* outerMap, innerMapList, additionalSheetsData, null, null);

*/

public static void exportToTemplateWithMultipleSheets1(HttpServletResponse response, String excelPath, String excelFileName,

Map<String, Object> outerMap, List<Map<String, Object>> innerMapList,

List<List<Map<String, Object>>> additionalSheetsData,

ExcelFillCellMergePrevColUtils excelFillCellMergePrevColUtils,

ExcelFillCellMergeStrategyUtils excelFillCellMergeStrategyUtils) throws IOException {

InputStream inputStream = new ClassPathResource(excelPath).getInputStream();

response.setContentType("application/vnd.ms-excel");

response.setCharacterEncoding("utf-8");

String fileName = URLEncoder.encode(excelFileName, "UTF-8");

response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");code>

ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())

.withTemplate(inputStream)

.registerWriteHandler(excelFillCellMergePrevColUtils)

.registerWriteHandler(excelFillCellMergeStrategyUtils)

.build();

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

// 处理第一个Sheet页的数据

WriteSheet writeSheet = EasyExcel.writerSheet().build();

if (null != innerMapList && innerMapList.size() > 0) {

FillWrapper listWrapper = new FillWrapper("list", innerMapList);

excelWriter.fill(listWrapper, fillConfig, writeSheet);

}

if (null != outerMap && outerMap.size() > 0) {

excelWriter.fill(outerMap, writeSheet);

}

// 处理额外的Sheet页的数据

for (int i = 0; i < additionalSheetsData.size(); i++) {

List<Map<String, Object>> sheetData = additionalSheetsData.get(i);

WriteSheet additionalSheet = EasyExcel.writerSheet(i + 1).sheetName("Sheet" + (i + 2)).build();

System.out.println("I+1:" + (i + 1) + "Sheet:" + "Sheet" + (i + 2));

if (null != sheetData && sheetData.size() > 0) {

FillWrapper additionalListWrapper = new FillWrapper("list", sheetData);

excelWriter.fill(additionalListWrapper, fillConfig, additionalSheet);

}

}

excelWriter.finish();

}

/**

* 导出数据到指定Excel

*

* @param response HttpServletResponse对象

* @param excelPath Excel模板地址

* @param excelFileName 文件名称

* @param outerMap 头部内容map

* @param innerMapList 表格内容list

* @param excelFillCellMergePrevColUtils 列合并参数

* @param excelFillCellMergeStrategyUtils 行合并参数

* @throws IOException 异常错误

*/

public static void exportToTemplate(HttpServletResponse response, String excelPath, String excelFileName, Map<String, Object> outerMap, List<Map<String, Object>> innerMapList,

ExcelFillCellMergePrevColUtils excelFillCellMergePrevColUtils, ExcelFillCellMergeStrategyUtils excelFillCellMergeStrategyUtils) throws IOException {

InputStream inputStream = new ClassPathResource(excelPath).getInputStream();

response.setContentType("application/vnd.ms-excel");

response.setCharacterEncoding("utf-8");

String fileName = URLEncoder.encode(excelFileName, "UTF-8");

response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");code>

ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())

.withTemplate(inputStream)

.registerWriteHandler(excelFillCellMergePrevColUtils)

.registerWriteHandler(excelFillCellMergeStrategyUtils)

.build();

WriteSheet writeSheet = EasyExcel.writerSheet().build();

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

if (null != innerMapList && innerMapList.size() > 0) {

FillWrapper listWrapper = new FillWrapper("list", innerMapList);

excelWriter.fill(listWrapper, fillConfig, writeSheet);

}

if (null != outerMap && outerMap.size() > 0) {

excelWriter.fill(outerMap, writeSheet);

}

excelWriter.finish();

}

/**

* 验证并获取excel单元格内的值

*

* @param columnData 列值,object类型

* @param rowIndex 行号

* @param columnIndex 列号

* @param fieldName 字段名称

* @param lengthLimit 限制长度数(null时不做判断)

* @param ifJudgeEmpty 是否需要判空(默认是)

* @return 字符串格式值

* @throws Exception 逻辑异常

*/

public static String checkValue(Object columnData, int rowIndex, int columnIndex, String fieldName, Integer lengthLimit,

Boolean ifJudgeEmpty) throws Exception {

String value = getStringValue(columnData);

ifJudgeEmpty = null == ifJudgeEmpty ? true : ifJudgeEmpty;

if (ifJudgeEmpty) {

//需要判空

if (StringUtils.isEmpty(value)) {

throw new Exception("第" + (rowIndex + 1) + "行,第" + (columnIndex + 1) + "列," + fieldName + "不能为空");

}

}

if (null != lengthLimit && lengthLimit > 0) {

//需要判断字符长度

if (StringUtils.isNotEmpty(value)) {

if (value.length() > lengthLimit) {

throw new Exception("第" + (rowIndex + 1) + "行,第" + (columnIndex + 1) + "列," + fieldName + "不能超过" + lengthLimit + "个字符");

}

}

}

return value;

}

/**

* String => LocalDate

* 入参str和pattern格式需要对应

*

* @param str

* @return LocalDate

*/

public static LocalDate str2LocalDate(String str) {

if (StringUtils.isEmpty(str)) {

return null;

}

if (str.indexOf("-") != -1 || str.indexOf("/") != -1) {

String pattern = str.indexOf("/") != -1 ? "yyyy/MM/dd" : "yyyy-MM-dd";

try {

//测试日期字符串是否符合日期

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);

return LocalDate.parse(str, dateTimeFormatter);

} catch (Exception e) {

pattern = str.indexOf("/") != -1 ? "yyyy/M/d" : "yyyy-M-d";

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);

return LocalDate.parse(str, dateTimeFormatter);

}

} else {

Calendar calendar = new GregorianCalendar(1900, 0, -1);

Date date = calendar.getTime();

int amount = Integer.parseInt(str);

if (amount > 0) {

Calendar calendar1 = Calendar.getInstance();

calendar1.setTime(date);

calendar1.add(Calendar.DAY_OF_YEAR, amount);

date = calendar.getTime();

}

return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

}

}

/**

* 获取String类型的值

*

* @param columnData 列值,object类型

* @return 字符串格式值

*/

public static String getStringValue(Object columnData) {

if (columnData == null) {

return null;

} else {

String res = columnData.toString().replace("[\\t\\n\\r]", "").trim();

return res;

// //判断是否是科学计数法 true是科学计数法,false不是科学计数法

// boolean isMache=SCIENTIFIC_COUNTING_METHOD_PATTERN.matcher(res).matches();

// if(isMache){

// BigDecimal resDecimal = new BigDecimal(res);

// return resDecimal.toPlainString();

// }else {

// return res;

// }

}

}

}

ExcelFillCellMergeStrategyUtils:

import com.alibaba.excel.metadata.CellData;

import com.alibaba.excel.metadata.Head;

import com.alibaba.excel.write.handler.CellWriteHandler;

import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;

import com.alibaba.excel.write.metadata.holder.WriteTableHolder;

import org.apache.poi.ss.usermodel.Cell;

import org.apache.poi.ss.usermodel.CellType;

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

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

import org.apache.poi.ss.util.CellRangeAddress;

import java.util.List;

/**

* 行合并工具类

*/

public class ExcelFillCellMergeStrategyUtils implements CellWriteHandler {

/**

* 合并字段的下标

*/

private int[] mergeColumnIndex;

/**

* 合并几行

*/

private int mergeRowIndex;

public ExcelFillCellMergeStrategyUtils(int mergeRowIndex, int[] mergeColumnIndex) {

this.mergeRowIndex = mergeRowIndex;

this.mergeColumnIndex = mergeColumnIndex;

}

@Override

public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,

Head head, Integer integer, Integer integer1, Boolean aBoolean) {

}

@Override

public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell,

Head head, Integer integer, Boolean aBoolean) {

}

@Override

public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,

CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {

}

@Override

public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,

List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {

//当前行

int curRowIndex = cell.getRowIndex();

//当前列

int curColIndex = cell.getColumnIndex();

if (curRowIndex > mergeRowIndex) {

for (int i = 0; i < mergeColumnIndex.length; i++) {

if (curColIndex == mergeColumnIndex[i]) {

this.mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);

break;

}

}

}

}

private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {

//获取当前行的当前列的数据和上一行的当前列列数据,通过上一行数据是否相同进行合并

//获取当前行的第一列

Cell firstNowCell = cell.getSheet().getRow(curRowIndex).getCell(curColIndex);

Object curData = firstNowCell.getCellTypeEnum() == CellType.STRING ? firstNowCell.getStringCellValue() : firstNowCell.getNumericCellValue();

Row preRow = cell.getSheet().getRow(curRowIndex - 1);

if (preRow == null) {

// 当获取不到上一行数据时,使用缓存sheet中数据

preRow = writeSheetHolder.getCachedSheet().getRow(curRowIndex - 1);

}

Cell preCell = preRow.getCell(curColIndex);

Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();

// 比较当前行的第一列的单元格与上一行是否相同,相同合并当前单元格与上一行

if (curData.equals(preData)) {

Sheet sheet = writeSheetHolder.getSheet();

List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();

boolean isMerged = false;

for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {

CellRangeAddress cellRangeAddr = mergeRegions.get(i);

// 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元

if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {

sheet.removeMergedRegion(i);

cellRangeAddr.setLastRow(curRowIndex);

sheet.addMergedRegion(cellRangeAddr);

isMerged = true;

}

}

// 若上一个单元格未被合并,则新增合并单元

if (!isMerged) {

CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);

sheet.addMergedRegion(cellRangeAddress);

}

}

}

}

ExcelFillCellMergePrevColUtils:

import com.alibaba.excel.metadata.CellData;

import com.alibaba.excel.metadata.Head;

import com.alibaba.excel.write.handler.CellWriteHandler;

import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;

import com.alibaba.excel.write.metadata.holder.WriteTableHolder;

import org.apache.poi.ss.usermodel.Cell;

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

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

import org.apache.poi.ss.util.CellRangeAddress;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

/**

* 列合并工具类

*/

public class ExcelFillCellMergePrevColUtils implements CellWriteHandler {

private static final String KEY = "%s-%s";

//所有的合并信息都存在了这个map里面

Map<String, Integer> mergeInfo = new HashMap<>();

public ExcelFillCellMergePrevColUtils() {

}

@Override

public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {

}

@Override

public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {

}

@Override

public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {

}

@Override

public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {

//当前行

int curRowIndex = cell.getRowIndex();

//当前列

int curColIndex = cell.getColumnIndex();

Integer num = mergeInfo.get(String.format(KEY, curRowIndex, curColIndex));

if (null != num) {

// 合并最后一行 ,列

this.mergeWithPrevCol(writeSheetHolder, cell, curRowIndex, curColIndex, num);

}

}

public void mergeWithPrevCol(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex, int num) {

Sheet sheet = writeSheetHolder.getSheet();

CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex, curRowIndex, curColIndex, curColIndex + num);

sheet.addMergedRegion(cellRangeAddress);

}

//num从第几列开始增加多少列,(6,2,7)代表的意思就是第6行的第2列至第2+7也就是9列开始合并

public void add(int curRowIndex, int curColIndex, int num) {

mergeInfo.put(String.format(KEY, curRowIndex, curColIndex), num);

}

}

3.上传Excel模板文件

        将excel模板文件上传至resources下的excel目录下(路径没有限制只要能够读取到)。

        模板excel文件截图(直接创建一个excel文件就行,我就不上传了)

4.接口Controller测试

实体类User

<code>

import lombok.AllArgsConstructor;

import lombok.Data;

import lombok.NoArgsConstructor;

import java.time.LocalDate;

@Data

@AllArgsConstructor

@NoArgsConstructor

public class User {

private Integer id; // 编号

private String name; // 姓名

private String idNumber; // 身份证号

private String phoneNumber; // 手机号

private LocalDate createTime; // 创建日期

}

接口ExcelController

import com.slice.reactminiospring.entity.User;

import com.slice.reactminiospring.util.ExcelUtils;

import jakarta.servlet.http.HttpServletResponse;

import lombok.extern.slf4j.Slf4j;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;

import java.time.format.DateTimeFormatter;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

@RestController

@Slf4j

@RequestMapping("/")

public class ExcelController {

//127.0.0.1:8080/generateWordForm

@GetMapping( "/generateExcelForm")

public void generateExcelForm(HttpServletResponse response) throws Exception {

// excelParam为入参对象,也可拆成单个参数来接收

// 根据入参查询用户数据集合

// List<User> resultList = userService.list();

List<User> resultList = new ArrayList<>();

resultList.add(new User(1, "张三", "513701199001011111", "15592111112", LocalDate.now()));

resultList.add(new User(2, "李四", "513701199001011112", "15592111113", LocalDate.now()));

resultList.add(new User(3, "王五", "513701199001011113", "15592111114", LocalDate.now()));

String title = "这个是Excel导出后Excel里面显示的标题";

Map<String, Object> outerMap = new HashMap<>(2);

outerMap.put("title", title);

List<Map<String, Object>> innerMapList = new ArrayList<>();

User item;

String startDate;

for (int i = 0; i < resultList.size(); ++i) {

item = resultList.get(i);

Map<String, Object> innerMap = new HashMap<>(16);

innerMap.put("index", i + 1);

innerMap.put("name", item.getName());

innerMap.put("idNumber", item.getIdNumber());

innerMap.put("phoneNumber", item.getPhoneNumber());

// 注意:时间需要转换成字符串形式

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

startDate = item.getCreateTime().format(formatter);

innerMap.put("createTime", startDate);

innerMapList.add(innerMap);

}

//注意这个文件创建的时候格式就要是xls,不然会报错,读取不到等问题

ExcelUtils.exportToTemplate(response, "excel/excel模板1.xls", title, outerMap, innerMapList, null, null);

}

}

Postman进行接口测试:

excel文件验证

上述就实现了将数据导出到excel指定模板中了,非常的好用。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。