说明:
1、代码实现了将表格内容与Collection<T>之间的转换,T代表对应的实体类。
2、表格内容可以设置起始行和起始列,如需扩展可根据代码继续扩展。
3、此文章参考了多篇文章,仅学习用。
目录
代码只是看着有点多,实际上不会很难,希望看完后对您有所帮助,同时也欢迎大家积极交流学习!
一、导入依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.16</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.16</version>
</dependency>
二、Annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelAnnotation {
// excel导出时标题显示的名字,如果没有设置Annotation属性,将不会被导出和导入
String exportName();
}
三、实体类
import com.innovative.annotation.ExcelAnnotation;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
/**
* 用于测试excel工具类的dto
*/
@Getter
@Setter
public class TestDTO {
@ExcelAnnotation(exportName = "用户名")
String userName;
@ExcelAnnotation(exportName = "登录名")
String loginName;
@ExcelAnnotation(exportName = "年龄")
Integer age;
@ExcelAnnotation(exportName = "收入")
Long money;
@ExcelAnnotation(exportName = "时间")
Date createTime;
}
四、excel工具类
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.*;
import com.innovative.annotation.ExcelAnnotation;
import org.apache.commons.lang3.StringUtils;
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.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/**
* Excel工具类
*/
public class ExcelUtils<T> {
/**
* 导入导出的类
*/
Class<T> clazz;
/**
* 日期格式
*/
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public ExcelUtils(Class<T> clazz) {
this.clazz = clazz;
}
/**
* 导出excel表格
*
* @param sheetName sheet标题(默认值为Sheet1)
* @param startRow 起始行号(第一行是标题,内容接在其后)
* @param startCol 起始列号(默认值为0)
* @param dataset 需要导出的数据集合(默认值为0)
* @param out 输出流
*/
public void exportExcel(String sheetName, Integer startRow, Integer startCol,
Collection<T> dataset, OutputStream out) throws Exception{
// 参数校验
if(Objects.isNull(dataset) || dataset.isEmpty()) {
System.out.println("导出数据为空!");
return;
}
if(Objects.isNull(out)){
throw new Exception("输出流为空!");
}
sheetName = StringUtils.isNotBlank(sheetName) ? sheetName : "Sheet1";
startRow = Objects.isNull(startRow) ? 0 : startRow;
startCol = Objects.isNull(startCol) ? 0 : startCol;
// 得到所有字段
Field[] fields = clazz.getDeclaredFields();
List<String> titleList = new ArrayList<>();
List<Method> getMethodList = new ArrayList<>();
// 遍历所有filed
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
ExcelAnnotation excelAnnotation = field.getAnnotation(ExcelAnnotation.class);
// 如果设置了annotation,则需要添加到标题集合中并解析出get方法
if (excelAnnotation != null) {
String exportName = excelAnnotation.exportName();
// 添加到标题列表
titleList.add(exportName);
// 需要导出字段get方法名
String fieldName = field.getName();
String getMethodName = "get"
+ fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
// 将get方法添加到集合中
Method getMethod = clazz.getMethod(getMethodName);
getMethodList.add(getMethod);
}
}
// 集合的迭代器
Iterator<T> its = dataset.iterator();
// 在内存中创建一个Excel文件对象
XSSFWorkbook workbook = new XSSFWorkbook();
// 创建Sheet页
XSSFSheet sheet = workbook.createSheet(sheetName);
// 设置表格默认列宽度为20个字节
sheet.setDefaultColumnWidth(20);
// 写入标题行
XSSFCellStyle titleStyle = workbook.createCellStyle();
ExcelStyle.setTitleStyle(workbook, titleStyle);
XSSFRow titleRow = sheet.createRow(startRow);
for (int i = 0; i < titleList.size(); i++) {
// 创建单元格并设置标题
XSSFCell cell = titleRow.createCell(startCol + i);
cell.setCellStyle(titleStyle);
XSSFRichTextString text = new XSSFRichTextString(titleList.get(i));
cell.setCellValue(text);
}
// 写入所有内容行
XSSFCellStyle bodyStyle = workbook.createCellStyle();
ExcelStyle.setBodyStyle(workbook, bodyStyle);
int index = startRow;
XSSFRow bodyRow = null;
while (its.hasNext()) {
//从第startRow+1行开始写,第startRow行是标题
index++;
bodyRow = sheet.createRow(index);
T curObject = (T) its.next();
for (int k = 0; k < getMethodList.size(); k++) {
XSSFCell cell = bodyRow.createCell(startCol + k);
cell.setCellStyle(bodyStyle);
Method getMethod = getMethodList.get(k);
Object value = getMethod.invoke(curObject);
String textValue = getValue(value);
cell.setCellValue(textValue);
}
}
workbook.write(out);
// 关闭资源
workbook.close();
}
/**
* 根据不同类型获取对应的内容(导出用)
* @param value
* @return
*/
public String getValue(Object value) {
String textValue = "";
if (value == null) return textValue;
if (value instanceof Boolean bValue) {
textValue = "是";
if (!bValue) {
textValue = "否";
}
} else if (value instanceof Date date) {
textValue = dateFormat.format(date);
} else {
textValue = value.toString();
}
return textValue;
}
/**
* 导入excel表格成Collection<T>
* @param file
* @param sheetName
* @param startRow
* @param startCol
* @return
* @throws Exception
*/
public Collection<T> importExcel(File file, String sheetName, Integer startRow, Integer startCol) throws Exception{
// 参数校验
if(Objects.isNull(file)){
System.out.println("文件为空!");
return null;
}
if(!file.getName().endsWith(".xlsx")){
throw new Exception("文件格式错误!");
}
startRow = Objects.isNull(startRow) ? 0 : startRow;
startCol = Objects.isNull(startCol) ? 0 : startCol;
Field[] fields = clazz.getDeclaredFields();
// 标有Annotation的字段标题名以及对应的set方法
Map<String, Method> fieldMap = new HashMap<>();
// 循环读取所有字段,找到标有Annotation的字段并将字段标题名和对应的set方法存到map中
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
ExcelAnnotation excelAnnotation = field.getAnnotation(ExcelAnnotation.class);
if (excelAnnotation != null) {
String fieldName = field.getName();
String setMethodName = "set"
+ fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
Method setMethod = clazz.getMethod(setMethodName, field.getType());
// 将这个method以Annotation的名字为key来存入
fieldMap.put(excelAnnotation.exportName(), setMethod);
}
}
// 将传入的File构造为FileInputStream;
FileInputStream in = new FileInputStream(file);
// 通过输入流读取指定的Excel文件
XSSFWorkbook workbook = new XSSFWorkbook(in);
// 得到对应sheet页
XSSFSheet sheet = StringUtils.isNotBlank(sheetName) ?
workbook.getSheet(sheetName) : workbook.getSheetAt(0);
// 得到标题行
XSSFRow titleRow = sheet.getRow(startRow);
// key:列号,value:对应标题名称
Map<Integer, String> titleMap = new HashMap<>();
// 获取标题行中的最后一列的列号
int lastColNum = titleRow.getLastCellNum();
for(int i = startCol; i < lastColNum; i++){
Cell cell = titleRow.getCell(i);
String value = cell.getStringCellValue();
titleMap.put(i, value);
}
// 解析内容
startRow++;
Collection<T> dataset = new ArrayList<>();
// 获取Sheet页中的最后一行的行号
int lastRowNum = sheet.getLastRowNum();
while(startRow <= lastRowNum){
Row bodyRow = sheet.getRow(startRow);
// 创建传入类的实例
T curObject = clazz.newInstance();
for(int i = startCol; i <= lastColNum; i++){
Cell cell = bodyRow.getCell(i);
// 此列对应的标题
String titleName = titleMap.get(i);
// 如果这一列的标题和类中的某一列的Annotation相同,则调用此类的的set方法,进行设值
if (fieldMap.containsKey(titleName)) {
Method setMethod = fieldMap.get(titleName);
// 得到setter方法的参数列表
Type[] parameterTypes = setMethod.getGenericParameterTypes();
// 只需要第一个参数的类型
String paramType = parameterTypes[0].toString();
cell.setCellType(CellType.STRING);
if (paramType.equals("class java.lang.String")) {
setMethod.invoke(curObject, cell.getStringCellValue());
} else if (paramType.equals("class java.util.Date")) {
setMethod.invoke(curObject, dateFormat.parse(cell.getStringCellValue()));
} else if (paramType.equals("class java.lang.Boolean")) {
Boolean boolname = true;
if (cell.getStringCellValue().equals("否")) {
boolname = false;
}
setMethod.invoke(curObject, boolname);
} else if (paramType.equals("class java.lang.Integer")) {
setMethod.invoke(curObject, Integer.parseInt(cell.getStringCellValue()));
} else if (paramType.equals("class java.lang.Long")) {
setMethod.invoke(curObject, Long.parseLong(cell.getStringCellValue()));
}
}
}
dataset.add(curObject);
startRow++;
}
return dataset;
}
}
五、设置标题与内容样式
import java.awt.Color;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/**
* Excel单元格样式
*/
public class ExcelStyle {
/**
* 表格标题单元格样式
* @param workbook
* @param style
* @return
*/
public static XSSFCellStyle setTitleStyle(XSSFWorkbook workbook, XSSFCellStyle style) {
// 设置背景色
style.setFillForegroundColor(new XSSFColor(new Color(255,255,255)));
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// 设置边框
style.setBorderBottom(XSSFCellStyle.BORDER_THIN); // 下边框
style.setBorderRight(XSSFCellStyle.BORDER_THIN);// 右边框
style.setBorderLeft(XSSFCellStyle.BORDER_THIN);// 左边框
style.setBorderTop(XSSFCellStyle.BORDER_THIN);// 上边框
// 设置单元格的中心水平对齐-居中
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
// 设置单元格的垂直对齐类型-居中
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 生成字体
XSSFFont font = workbook.createFont();
// 设置字体类型
font.setFontName("微软雅黑");
// 设置字体大小
font.setFontHeightInPoints((short) 10);
// 粗体字体
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
// 把字体应用到当前的样式
style.setFont(font);
return style;
}
/**
* 表格主体单元格样式
* @param workbook
* @param style
* @return
*/
public static XSSFCellStyle setBodyStyle(XSSFWorkbook workbook, XSSFCellStyle style) {
// 设置背景色
// style.setFillForegroundColor(new XSSFColor(new Color(255,255,255)));
// style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// 设置边框
style.setBorderBottom(XSSFCellStyle.BORDER_THIN); // 下边框
style.setBorderRight(XSSFCellStyle.BORDER_THIN);// 右边框
style.setBorderLeft(XSSFCellStyle.BORDER_THIN);// 左边框
style.setBorderTop(XSSFCellStyle.BORDER_THIN);// 上边框
// 生成字体
XSSFFont font = workbook.createFont();
// 字体类型
font.setFontName("微软雅黑");
// 设置字体大小
font.setFontHeightInPoints((short) 9);
// 普通字体
font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
// 把字体应用到当前的样式
style.setFont(font);
return style;
}
}
六、测试类
import com.innovative.service.dto.TestDTO;
import com.innovative.utils.ExcelUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@SpringBootTest
public class ExcelUtilsTest {
@Test
public void importTest() throws Exception {
ExcelUtils<TestDTO> test = new ExcelUtils<>(TestDTO.class);
File file = new File("D:\\excelTest.xlsx");
List<TestDTO> result = (ArrayList<TestDTO>) test.importExcel(file,null,null,null);
// 输出导入信息
for (int i = 0; i < result.size(); i++) {
TestDTO testDTO = result.get(i);
System.out.println("导入的信息为:" + testDTO.getUserName() + "-----" + testDTO.getLoginName() + "----" + testDTO.getAge()
+ "---" + testDTO.getMoney() + "-----" + testDTO.getCreateTime());
}
System.out.println("共转化为List的行数为:" + result.size());
}
@Test
public void exportTest() throws Exception {
// 构建一个TestDTO来模拟导出
List<TestDTO> list = new ArrayList<>();
for (int i = 0; i < 5000; i++) {
TestDTO pojo = new TestDTO();
pojo.setLoginName("登录名"+i);
pojo.setUserName("用户名"+i);
pojo.setMoney(new Long(1000+i));
pojo.setCreateTime(new Date());
pojo.setAge(28);
list.add(pojo);
}
// 构造输出对象,可以从response输出,直接向用户提供下载
OutputStream out = new FileOutputStream("D:\\excelTest.xlsx");
// excel工具类
ExcelUtils<TestDTO> ex = new ExcelUtils<>(TestDTO.class);
// 导出
ex.exportExcel(null,null,null, list, out);
out.close();
}
}