SpringBoot2:web开发常用功能实现及原理解析-整合EasyExcel实现Excel导入导出功能

文章目录

1、工程包结构

主要是这5个Java类

2、导入EasyExcel包

这里同时贴出其他相关springboot的基础包

xml 复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 引入easyExcel依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.6</version>
        </dependency>

3、Java代码

ExcelSysUser

java 复制代码
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.ContentStyle;
import com.alibaba.excel.annotation.write.style.HeadFontStyle;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.Data;
import lombok.ToString;
import org.apache.poi.ss.usermodel.HorizontalAlignment;

@ContentRowHeight(25)
@HeadRowHeight(15)
@ColumnWidth(25)
@HeadFontStyle(fontHeightInPoints=9)
@ContentStyle(horizontalAlignment= HorizontalAlignment.CENTER)
@Data
@ToString
public class ExcelSysUser {

	public ExcelSysUser(){

	}

	public ExcelSysUser(String loginName, String userName, String userPwd){
		this.loginName = loginName;
		this.userName = userName;
		this.userPwd = userPwd;
	}

	@ExcelProperty(value = "登录名",index = 0)
	private String loginName;

	@ExcelProperty(value = "用户名",index = 1)
	private String userName;

	@ExcelProperty(value = "密码",index = 2)
	private String userPwd;

}

ExcelFillCellMergeHandler

java 复制代码
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 ExcelFillCellMergeHandler implements CellWriteHandler {

	//需要合并的列
	private int[] mergeColumnIndex;
	//从哪一列开始合并
	private int mergeRowIndex;

	public ExcelFillCellMergeHandler() {
	}

	public ExcelFillCellMergeHandler(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]) {
					mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
					break;
				}
			}
		}
	}

	/**
	 * 当前单元格向上合并
	 *
	 * @param writeSheetHolder
	 * @param cell             当前单元格
	 * @param curRowIndex      当前行
	 * @param curColIndex      当前列
	 */
	private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
		Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
		Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
		Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
		// 将当前单元格数据与上一个单元格数据比较
		Boolean dataBool = preData.equals(curData);
		Boolean bool = cell.getRow().getCell(0).getStringCellValue().equals(cell.getSheet().getRow(curRowIndex - 1).getCell(0).getStringCellValue());
		if (dataBool && bool) {
			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);
			}
		}
	}

}

ExcelListener

java 复制代码
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;

import java.util.ArrayList;
import java.util.List;

/**
 * 解析监听器,
 * 每解析一行会回调invoke()方法。
 * 整个excel解析结束会执行doAfterAllAnalysed()方法
 */
public class ExcelListener extends AnalysisEventListener {

	private List<Object> datas = new ArrayList<>();

	public List<Object> getDatas() {
		return datas;
	}

	public void setDatas(List<Object> datas) {
		this.datas = datas;
	}

	/**
	 * 逐行解析
	 * object : 当前行的数据
	 */
	@Override
	public void invoke(Object object, AnalysisContext context) {
		//当前行
		// context.getCurrentRowNum()
		if (object != null) {
			datas.add(object);
		}
	}


	/**
	 * 解析完所有数据后会调用该方法
	 */
	@Override
	public void doAfterAllAnalysed(AnalysisContext context) {
		//解析结束销毁不用的资源
	}
}

EasyExcelUtil

java 复制代码
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.atguigu.boot.handler.ExcelFillCellMergeHandler;
import com.atguigu.boot.listener.ExcelListener;
import org.springframework.web.multipart.MultipartFile;

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

/**
 * EasyExcel工具类
 */
public class EasyExcelUtil {

	/**
	 * 读取 Excel(多个 sheet)
	 *
	 * @param excel 文件
	 * @param rowModel 实体类映射
	 * @return Excel 数据 list
	 */
	public static List<Object> readExcel(MultipartFile excel, Object rowModel) throws IOException {
		String filename = excel.getOriginalFilename();
		if (filename == null || (!filename.toLowerCase().endsWith(".xls") && !filename.toLowerCase().endsWith(".xlsx"))) {
			throw new RuntimeException("文件格式错误!");
		}
		ExcelListener excelListener = new ExcelListener();
		EasyExcel.read(excel.getInputStream(),rowModel.getClass(),excelListener).doReadAll();
		return excelListener.getDatas();
	}

	/**
	 * 导出 Excel :一个 sheet,带表头
	 *
	 * @param response HttpServletResponse
	 * @param list 数据 list
	 * @param fileName 导出的文件名
	 * @param sheetName 导入文件的 sheet 名
	 * @param object 映射实体类,Excel 模型
	 */
	public static void writeExcel(HttpServletResponse response, List<?> list, String fileName,
								  String sheetName, Object object) {
		EasyExcel.write(getOutputStream(fileName, response),object.getClass())
				.excelType(ExcelTypeEnum.XLSX)
				.autoCloseStream(Boolean.TRUE)
				.sheet(sheetName)
				.doWrite(list);
	}

	/**
	 * 导出 Excel 自动合并单元格
	 * @param response HttpServletResponse
	 * @param list 数据 list
	 * @param fileName 导出的文件名
	 * @param sheetName 导入文件的 sheet 名
	 * @param object 映射实体类,Excel 模型
	 * @param mergeColumnIndex 需要合并的列
	 * @param mergeRowIndex 从哪一列开始合并
	 */
	public static void writeMergeExcel(HttpServletResponse response, List<?> list, String fileName,
									   String sheetName, Object object, int[] mergeColumnIndex, int mergeRowIndex) {
		EasyExcel.write(getOutputStream(fileName, response),object.getClass())
				.excelType(ExcelTypeEnum.XLSX)
				.autoCloseStream(Boolean.TRUE)
				.registerWriteHandler(new ExcelFillCellMergeHandler(mergeRowIndex,mergeColumnIndex))
				.sheet(sheetName)
				.doWrite(list);
	}

	/**
	 * 导出文件时为Writer生成OutputStream
	 */
	private static OutputStream getOutputStream(String fileName, HttpServletResponse response) {
		//创建本地文件
		fileName = fileName + ".xls";

		try {
			fileName = new String(fileName.getBytes(), "ISO-8859-1");
			response.addHeader("Content-Disposition", "attachment;filename=" + fileName);

			return response.getOutputStream();
		} catch (Exception e) {
			throw new RuntimeException("导出异常!");
		}
	}

}

EasyExcelLoadsController

java 复制代码
import com.atguigu.boot.bean.ExcelSysUser;
import com.atguigu.boot.utils.EasyExcelUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

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

@RestController
@RequestMapping("/excel")
public class EasyExcelLoadsController {

	/**
	 * 用户信息导出Excel
	 */
	@RequestMapping(value = "/exportSysUser",method = RequestMethod.GET)
	public void exportSysUser(HttpServletResponse response){
		List<ExcelSysUser> excelSysUsers = new ArrayList<>();
		ExcelSysUser excelSysUser1 = new ExcelSysUser("张三", "zhangsan002", "zsmm123");
		ExcelSysUser excelSysUser2 = new ExcelSysUser("张三", "zhangsan003", "zsmm456");
		ExcelSysUser excelSysUser3 = new ExcelSysUser("张三", "zhangsan001", "zsmm789");
		ExcelSysUser excelSysUser4 = new ExcelSysUser("李四", "zhangsan001", "zsmm123");
		ExcelSysUser excelSysUser5 = new ExcelSysUser("李四", "zhangsan001", "zsmm456");
		excelSysUsers.add(excelSysUser1);
		excelSysUsers.add(excelSysUser2);
		excelSysUsers.add(excelSysUser3);
		excelSysUsers.add(excelSysUser4);
		excelSysUsers.add(excelSysUser5);
		EasyExcelUtil.writeExcel(response, excelSysUsers,"用户信息","用户信息", new ExcelSysUser());

	}

	/**
	 * 用户信息导出Excel(合并单元格)
	 */
	@RequestMapping(value = "/exportMergeSysUser",method = RequestMethod.GET)
	public void exportMergeSysUser(HttpServletResponse response){
		List<ExcelSysUser> excelSysUsers = new ArrayList<>();
		ExcelSysUser excelSysUser1 = new ExcelSysUser("张三", "zhangsan002", "zsmm123");
		ExcelSysUser excelSysUser2 = new ExcelSysUser("张三", "zhangsan003", "zsmm456");
		ExcelSysUser excelSysUser3 = new ExcelSysUser("张三", "zhangsan001", "zsmm789");
		ExcelSysUser excelSysUser4 = new ExcelSysUser("李四", "zhangsan001", "zsmm123");
		ExcelSysUser excelSysUser5 = new ExcelSysUser("李四", "zhangsan001", "zsmm456");
		excelSysUsers.add(excelSysUser1);
		excelSysUsers.add(excelSysUser2);
		excelSysUsers.add(excelSysUser3);
		excelSysUsers.add(excelSysUser4);
		excelSysUsers.add(excelSysUser5);
		int[] mergeColumnIndex = {0,1};
		int mergeRowIndex = 0;
		EasyExcelUtil.writeMergeExcel(response, excelSysUsers,"用户信息","用户信息", new ExcelSysUser(), mergeColumnIndex, mergeRowIndex);

	}

	@RequestMapping(value = "/importSysUser",method = RequestMethod.POST)
	public void importSysUser(MultipartFile excel){
		List<Object> dataList = null;
		try {
			dataList = EasyExcelUtil.readExcel(excel, new ExcelSysUser());
		} catch (IOException e) {
			e.printStackTrace();
		}
		dataList.forEach(o -> System.out.println(o.toString()));
	}

}

4、测试Excel

导入需要准备下图中的数据,导出直接浏览器访问接口即可。

相关推荐
IT毕设实战小研2 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
一只爱撸猫的程序猿3 小时前
使用Spring AI配合MCP(Model Context Protocol)构建一个"智能代码审查助手"
spring boot·aigc·ai编程
甄超锋4 小时前
Java ArrayList的介绍及用法
java·windows·spring boot·python·spring·spring cloud·tomcat
武昌库里写JAVA6 小时前
JAVA面试汇总(四)JVM(一)
java·vue.js·spring boot·sql·学习
Pitayafruit7 小时前
Spring AI 进阶之路03:集成RAG构建高效知识库
spring boot·后端·llm
zru_96027 小时前
Spring Boot 单元测试:@SpyBean 使用教程
spring boot·单元测试·log4j
甄超锋8 小时前
Java Maven更换国内源
java·开发语言·spring boot·spring·spring cloud·tomcat·maven
还是鼠鼠8 小时前
tlias智能学习辅助系统--Maven 高级-私服介绍与资源上传下载
java·spring boot·后端·spring·maven
舒一笑13 小时前
Started TttttApplication in 0.257 seconds (没有 Web 依赖导致 JVM 正常退出)
jvm·spring boot·后端
javadaydayup14 小时前
Apollo 凭什么能 “干掉” 本地配置?
spring boot·后端·spring