首先是pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com</groupId>
<artifactId>yaya</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>test-thing</name>
<description>test-thing</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.4.3</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>4.1.0</version>
</dependency>
<!-- EasyExcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.1</version>
</dependency>
<!-- 时间操作组件 -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.5</version>
</dependency>
<!-- 时间toLocalDateTime -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<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.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>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.yaya.TestThingApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
yml
server:
port: 1001
utils:
package com.yaya.utils.excel;
import org.springframework.beans.BeanUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @Description Object与实体类转换工具类
*/
public class BeanConvert {
private BeanConvert(){}
/**
* 将List<Object> 转换为List<Bean>
* @param sources 源对象
* @param targetClass 目标类
* @param <T>
* @return
*/
public static <T> List<T> objectConvertBean(List<?> sources, Class<T> targetClass) {
List<?> sourcesObj = sources;
if (sourcesObj == null) {
sourcesObj = Collections.emptyList();
}
List<T> targets = new ArrayList<>(sourcesObj.size());
convert(sourcesObj, targets, targetClass);
return targets;
}
/**
* 复制源对象到目的对象
* 注意:
* org.springframework.beans.BeanUtils.copyProperties 是一个Spring提供的名称相同的工具类
* 但它不支持类型自动转换,如果某个类型属性不同,则不予转换那个属性
* org.apache.commons.beanutils.BeanUtils 是一个Apache提供的名称相同的工具类
* 支持类型自动转换,如Date类型会自动转换为字符串
* @param sources 源对象
* @param targets 目的对象
* @param targetClass 目标类
* @param <T>
*/
private static <T> void convert(List<?> sources, List<T> targets, Class<T> targetClass) {
if (sources == null) {
return;
}
if (targets == null) {
return;
}
targets.clear();
for (Object obj : sources) {
try {
T target = targetClass.newInstance();
targets.add(target);
BeanUtils.copyProperties(obj, target);
} catch (Exception e) {
return;
}
}
}
}
package com.yaya.utils.excel;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.yaya.excel.ExcelListener;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* @Description Excel读写工具类
*/
public class ExcelUtils {
private ExcelUtils(){}
/**
* 读取Excel(一个sheet)
* @param excel 文件
* @param clazz 实体类
* @param sheetNo sheet序号
* @return 返回实体列表(需转换)
*/
public static <T> List<T> readExcel(MultipartFile excel, Class<T> clazz,int sheetNo) {
ExcelListener excelListener = new ExcelListener();
ExcelReader excelReader = getReader(excel,clazz,excelListener);
if (excelReader == null) {
return new ArrayList<>();
}
ReadSheet readSheet = EasyExcel.readSheet(sheetNo).build();
excelReader.read(readSheet);
excelReader.finish();
return BeanConvert.objectConvertBean(excelListener.getDataList(), clazz);
}
/**
* 读取Excel(多个sheet可以用同一个实体类解析)
* @param excel 文件
* @param clazz 实体类
* @return 返回实体列表(需转换)
*/
public static <T> List<T> readExcel(MultipartFile excel, Class<T> clazz) {
ExcelListener excelListener = new ExcelListener();
ExcelReader excelReader = getReader(excel,clazz,excelListener);
if (excelReader == null) {
return new ArrayList<>();
}
List<ReadSheet> readSheetList = excelReader.excelExecutor().sheetList();
for (ReadSheet readSheet:readSheetList){
excelReader.read(readSheet);
}
excelReader.finish();
return BeanConvert.objectConvertBean(excelListener.getDataList(), clazz);
}
/**
* 导出Excel(一个sheet)
*
* @param response HttpServletResponse
* @param list 数据list
* @param fileName 导出的文件名
* @param sheetName 导入文件的sheet名
* @param clazz 实体类
*/
public static <T> void writeExcel(HttpServletResponse response,List<T> list, String fileName, String sheetName, Class<T> clazz) {
OutputStream outputStream = getOutputStream(response, fileName);
ExcelWriter excelWriter = EasyExcel.write(outputStream, clazz).build();
WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
excelWriter.write(list, writeSheet);
excelWriter.finish();
}
/**
* 导出Excel(带样式)
*
* @return
*/
public static <T> void writeStyleExcel(HttpServletResponse response,List<T> list, String fileName, String sheetName, Class<T> clazz) {
//表头策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
//背景浅灰
headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short)20);
headWriteCellStyle.setWriteFont(headWriteFont);
//内容策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
//这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 否则无法显示背景颜色;头默认了FillPatternType
contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
//背景浅绿
contentWriteCellStyle.setFillForegroundColor(IndexedColors.LIGHT_GREEN.getIndex());
WriteFont contentWriteFont = new WriteFont();
//字体大小
contentWriteFont.setFontHeightInPoints((short)15);
contentWriteCellStyle.setWriteFont(contentWriteFont);
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
OutputStream outputStream = getOutputStream(response, fileName);
EasyExcel.write(outputStream, clazz).registerWriteHandler(horizontalCellStyleStrategy).sheet(sheetName).doWrite(list);
}
/**
* 导出Excel(动态表头)
* write时不传入class,table时传入并设置needHead为false
* @return
*/
public static <T> void writeDynamicHeadExcel(HttpServletResponse response,List<T> list, String fileName, String sheetName, Class<T> clazz,List<List<String>> headList) {
OutputStream outputStream = getOutputStream(response, fileName);
EasyExcel.write(outputStream)
.head(headList)
.sheet(sheetName)
.table().head(clazz).needHead(Boolean.FALSE)
.doWrite(list);
}
/**
* 导出时生成OutputStream
*/
private static OutputStream getOutputStream(HttpServletResponse response,String fileName) {
//创建本地文件
String filePath = fileName + ".xlsx";
File file = new File(filePath);
try {
if (!file.exists() || file.isDirectory()) {
file.createNewFile();
}
fileName = new String(filePath.getBytes(), "ISO-8859-1");
response.addHeader("Content-Disposition", "filename=" + fileName);
return response.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 返回ExcelReader
* @param excel 文件
* @param clazz 实体类
* @param excelListener
*/
private static <T> ExcelReader getReader(MultipartFile excel, Class<T> clazz, ExcelListener excelListener) {
String filename = excel.getOriginalFilename();
try {
if (filename == null || (!filename.toLowerCase().endsWith(".xls") && !filename.toLowerCase().endsWith(".xlsx"))) {
return null;
}
InputStream inputStream = new BufferedInputStream(excel.getInputStream());
ExcelReader excelReader = EasyExcel.read(inputStream, clazz, excelListener).build();
inputStream.close();
return excelReader;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.yaya.excel.excelDto;
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.HeadRowHeight;
import lombok.Data;
/**
@ExcelProperty
这是最常用的一个注解,注解中有三个参数value,index,converter
分别代表列明,列序号,数据转换方式,value和index只能二选一,通常不用设置converter
@ColumnWith
用于设置列宽度的注解,注解中只有一个参数value,value的单位是字符长度,
最大可以设置255个字符,因为一个excel单元格最大可以写入的字符个数就是255个字符。
@ContentFontStyle
用于设置单元格内容字体格式的注解
@ContentLoopMerge
用于设置合并单元格的注解
@ContentRowHeight
用于设置行高
@ContentStyle
设置内容格式注解
@HeadFontStyle
用于定制标题字体格式
@HeadRowHeight
设置标题行行高
@HeadStyle
设置标题样式
@ExcelIgnore
不将该字段转换成Excel
@ExcelIgnoreUnannotated
没有注解的字段都不转换
*/
@ContentRowHeight(20)
@HeadRowHeight(25)
@ColumnWidth(25)
@Data
public class ExportModel {
@ExcelProperty(value = "姓名" ,index = 0)
private String name;
@ExcelProperty(value = "性别" ,index = 1)
private String sex;
@ExcelProperty(value = "年龄" ,index = 2)
private Integer age;
@ExcelProperty(value= "出生时间" ,index = 3)
private String date;
}
package com.yaya.excel.excelDto;
import java.util.ArrayList;
import java.util.List;
public class ExportModelHead {
public static List<List<String>> head() {
List<List<String>> headList = new ArrayList<>();
List<String> nameHead = new ArrayList<>();
nameHead.add("姓名");
List<String> genderHead = new ArrayList<>();
genderHead.add("性别");
List<String> ageHead = new ArrayList<>();
ageHead.add("年龄");
List<String> dateHead =new ArrayList<>();
dateHead.add("出生时间");
headList.add(nameHead);
headList.add(genderHead);
headList.add(ageHead);
headList.add(dateHead);
return headList;
}
}
package com.yaya.excel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.ArrayList;
import java.util.List;
/**
* @Description 监听类
*/
public class ExcelListener extends AnalysisEventListener {
//可以通过实例获取该值
private List<Object> dataList = new ArrayList<>();
@Override
public void invoke(Object object, AnalysisContext context) {
//数据存储到list,供批量处理,或后续自己业务逻辑处理。
dataList.add(object);
handleBusinessLogic();
/*
如数据过大,可以进行定量分批处理
if(dataList.size()>=200){
handleBusinessLogic();
dataList.clear();
}
*/
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
//非必要语句,查看导入的数据
System.out.println("导入的数据 " + dataList.toString());
//解析结束销毁不用的资源
dataList.clear();
}
//根据业务自行实现该方法,例如将解析好的dataList存储到数据库中
private void handleBusinessLogic() {
}
public List<Object> getDataList() {
return dataList;
}
public void setDataList(List<Object> dataList) {
this.dataList = dataList;
}
}
package com.yaya.controller;
import com.yaya.excel.excelDto.ExportModel;
import com.yaya.excel.excelDto.ExportModelHead;
import com.yaya.utils.DateUtils;
import com.yaya.utils.excel.ExcelUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping(value = "/excel")
public class ExcelController {
@GetMapping(value = "/export")
public void writeExcel(HttpServletResponse response) {
List<ExportModel> list = getList();
String fileName = "Excel导出测试";
String sheetName = "sheet1";
ExcelUtils.writeDynamicHeadExcel(response, list, fileName, sheetName, ExportModel.class, ExportModelHead.head());
}
/* 填充数据*/
private List<ExportModel> getList() {
List<ExportModel> modelList = new ArrayList<>();
Date date=new Date();
ExportModel firstModel = new ExportModel();
firstModel.setName("李明");
firstModel.setSex("男");
firstModel.setAge(20);
firstModel.setDate(DateUtils.format(date));
modelList.add(firstModel);
ExportModel secondModel = new ExportModel();
secondModel.setName("珍妮");
secondModel.setSex("女");
secondModel.setAge(19);
secondModel.setDate(DateUtils.format(date));
modelList.add(secondModel);
return modelList;
}
}
访问路径:
localhost:1001/excel/export
测试demo地址:https://gitee.com/yang-saiya/easyexcel