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

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

相关推荐
摇滚侠4 分钟前
Spring Boot 3零基础教程,WEB 开发 通过配置类代码方式修改静态资源配置 笔记32
java·spring boot·笔记
小咕聊编程36 分钟前
【含文档+PPT+源码】基于spring boot的固定资产管理系统
java·spring boot·后端
马尚道1 小时前
SpringBoot开发双11商品服务系统 | 已完结
spring boot
韩立学长1 小时前
【开题答辩实录分享】以《自然灾害隐患点管理信息系统》为例进行答辩实录分享
数据库·spring boot
我命由我123451 小时前
Spring Cloud - Spring Cloud 注册中心与服务提供者(Spring Cloud Eureka 概述、微服务快速入门、微服务应用实例)
java·spring boot·spring·spring cloud·微服务·eureka·java-ee
一线大码2 小时前
SpringBoot 优雅实现接口的多实现类方式
java·spring boot·后端
Q_Q19632884753 小时前
python+uniapp基于微信小程序的助眠小程序
spring boot·python·小程序·django·flask·uni-app·node.js
摇滚侠3 小时前
Spring Boot 3零基础教程,WEB 开发 Thymeleaf 属性优先级 行内写法 变量选择 笔记42
java·spring boot·笔记
摇滚侠3 小时前
Spring Boot 3零基础教程,WEB 开发 Thymeleaf 总结 热部署 常用配置 笔记44
java·spring boot·笔记
十年小站3 小时前
一、新建一个SpringBoot3项目
java·spring boot