最近工作的时候,正在写关于Excel导出功能,由于当前使用的工具类不太灵活和不易看懂,自己从头写又很浪费时间等原因,我决定自己写一款很简单的Excel导出的工具类,仅仅是出于学习的目的。
基于HSSFWorkbook,介绍如下:
首先需要一个Maven依赖:
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poiartifactId>
<version>5.0.0version>
dependency>
工具类的名称是ExcelUtil,类中包含两个主要的方法可以来调用:
本方法有两个形参,分别是String fileName(文件名), List
dataList(数据列表)
具体使用方法如下:
首先创建一个数据列表,一般都是从数据库获取,这里我手动创建一个:
public static List<List<Object>> listData() {
List<List<Object>> dataList = new ArrayList<>(); //所需要的数据列表的类型
String[] thStrings = {"id", "名字", "性别", "年龄", "籍贯", "学历"};
//表头数据
ArrayList<Object> th = new ArrayList<>(Arrays.asList(thStrings));
dataList.add(th); // 将表头数据放入数据列表中
//表格数据
ArrayList<Object> data = new ArrayList<>();
data.add("001");
data.add("iKun");
data.add("man");
data.add(18);
data.add("美国");
data.add("rap博士");
for (int i = 0; i < 200; i++) {
dataList.add(data); // 循环将200个iKun放入数据列表中
}
return dataList;
}
在main中使用:
public static void main(String[] args) {
String title = "Excel"; // 文件名
List<List<Object>> listData = listData(); // 数据列表
ExcelUtil excelUtil = new ExcelUtil();
Boolean result = excelUtil.exportExcelList(title, listData);
System.out.println("result = " + result);
}
第二个方法是基于类的的反射和注解,主要是导出对应的实体类对象列表数据
exportExcelClass形参是三个,分别是String fileName(导出Excel的文件名), Class>
aClass(导出对应实体类类的反射), List dataList(对象集合的数据列表)
本方法是基于类的反射和注解实现的,首先在需要导出的实体类中的属性上方添加一注解,如下:
此注解有两个参数:value(表头)order(表格的列顺序,从小到大,从左向右排列,默认值为0)
将注解写在实体类的属性上以后,还是首先创建一个数据列表:
private static List<Student> studentListData() {
List<Student> studentList = new ArrayList<>();
Student iKun = new Student(18, "KunKun", 2.5, new Date());
for (int i = 0; i < 10; i++) {
studentList.add(iKun);
}
return studentList;
}
在main中使用:
public static void main(String[] args) {
String title = "iKun花名册"; // 文件名
List<Student> studentList = studentListData(); //数据列表
ExcelUtil<Student> excelUtil = new ExcelUtil<>();
Boolean aBoolean = excelUtil.exportExcelClass(title, Student.class, studentList);
System.out.println("aBoolean = " + aBoolean);
}
最终导出的结果:
上述就是工具类的使用。
类有以下几个属性和方法:
其中 wb; getWb() getSheet() outputFile() 不必过于关注。
主要是剩余方法:
setCellStyle(设置单元格的样式)
exportExcelClass(根据实体类导出数据)
exportExcelList(根据list列表导出数据)
其中exportExcelClass调用了exportExcelList,exportExcelList调用了setCellStyle
1、表头样式
2、数据样式
数据分为文本数据和数字数据,可根据需要修改
注解接口类:
import java.lang.annotation.*;
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface ExportExcel {
String value() default ""; //表头
int order() default 0; // 顺序
}
工具实现类:
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
/**
* 一个Excel文件对应于一个workbook(HSSFWorkbook),
* 一个workbook可以有多个sheet(HSSFSheet)组成,
* 一个sheet是由多个row(HSSFRow)组成,
* 一个row是由多个cell(HSSFCell)组成。
*/
public class ExcelUtil<T> {
private final HSSFWorkbook wb = new HSSFWorkbook();
public HSSFWorkbook getWb() {
return wb;
}
/**
* 获取HSSFSheet,内部方法不必关注
*
* @param fileName 文件名
* @param wb HSSFWorkbook
* @return HSSFSheet
*/
private static HSSFSheet getSheet(String fileName, HSSFWorkbook wb) {
return wb.createSheet(fileName);
}
/**
* 通过类的反射导出 Excel
*
* @param fileName 文件名
* @param aClass 类对象
* @param dataList 数据列表
* @return 是否成功
*/
public Boolean exportExcelClass(String fileName, Class<?> aClass, List<T> dataList) {
List<Object> thRow = new ArrayList<>(); //表头数据
List<List<Object>> thOrderList = new ArrayList<>(); //存放数据和顺序
for (Field declaredField : aClass.getDeclaredFields()) { //循环遍历对象的属性列表
if (declaredField.isAnnotationPresent(ExportExcel.class)) { //找到被注解的属性
List<Object> orderValues = new ArrayList<>();
int order = declaredField.getAnnotation(ExportExcel.class).order(); //获取属性的order
String value = declaredField.getAnnotation(ExportExcel.class).value();//取出属性注解的value值
orderValues.add(order);
orderValues.add(value);
thOrderList.add(orderValues);
}
thOrderList.sort(Comparator.comparingInt(a -> (Integer) a.get(0))); //排序
}
for (List<Object> objects : thOrderList) {
thRow.add(objects.get(1));
}
List<List<Object>> lists = new ArrayList<>(); //表格数据
lists.add(thRow); //将表头数据加入
for (T t : dataList) { //循环遍历对象列表
Field[] declaredFields = t.getClass().getDeclaredFields(); //反射得到对象的属性列表
List<List<Object>> orderList = new ArrayList<>(); //存放数据和顺序
for (Field declaredField : declaredFields) { //循环遍历对象的属性
if (declaredField.isAnnotationPresent(ExportExcel.class)) {
int order = declaredField.getAnnotation(ExportExcel.class).order(); //获取属性的order
String name = declaredField.getName(); //获取属性的name
String getValueMethodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1); // 获取属性的get方法
Method method = null;
try {
method = t.getClass().getMethod(getValueMethodName);
Object invoke = method.invoke(t);
if (invoke == null) {
invoke = "";
}
List<Object> list = new ArrayList<>();
list.add(order);
list.add(invoke);
orderList.add(list);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
orderList.sort(Comparator.comparingInt(a -> (Integer) a.get(0))); //排序
ArrayList<Object> rowList = new ArrayList<>();
for (List<Object> orderData : orderList) {
rowList.add(orderData.get(1));
}
lists.add(rowList);
}
return exportExcelList(fileName, lists);
}
/**
* 通过list数据集合导出
*
* @param fileName 文件名
* @param dataList 数据列表(list)
* @return 导出是否成功
*/
public Boolean exportExcelList(String fileName, List<List<Object>> dataList) {
HSSFSheet sheet = getSheet(fileName, wb);
int thSize = dataList.get(0).size() - 1; //表头数据列表长度
//标题内容 col列 row行
CellStyle titleStyle = setCellStyle("Arial", 16, true, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);//设置title单元格样式
HSSFRow titleRow = sheet.createRow(0);
HSSFCell titleCell = titleRow.createCell(0);
titleCell.setCellValue(fileName);
/*
合并单元格
第一个参数:第一个单元格的行数(从0开始)
第二个参数:第二个单元格的行数(从0开始)
第三个参数:第一个单元格的列数(从0开始)
第四个参数:第二个单元格的列数(从0开始)
*/
CellRangeAddress range = new CellRangeAddress(0, 0, 0, thSize);
sheet.addMergedRegion(range);
titleCell.setCellStyle(titleStyle);
//设置列的宽度
int size = dataList.get(0).size();
int[] colSize = new int[size];
for (List<Object> data : dataList) {
for (int i = 0; i < data.size(); i++) {
int length = data.get(i).toString().length();
if (colSize[i] < length) {
colSize[i] = length; //获取每一列中最长的数据
}
}
}
for (int i = 0; i < colSize.length; i++) {
sheet.setColumnWidth(i, 2000 + colSize[i] * 200); ///设置列的宽度
}
//表头行数
int rowId = 1;
//数据
CellStyle style = setCellStyle("Arial", 12, false, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
CellStyle numStyle = setCellStyle("Arial", 12, false, HorizontalAlignment.LEFT, VerticalAlignment.CENTER);
for (List<Object> strings : dataList) {
HSSFRow row = sheet.createRow(rowId);
for (int i = 0; i < strings.size(); i++) {
HSSFCell cell = row.createCell(i);
//表头的样式
if (rowId == 1) {
CellStyle thStyle = setCellStyle("Arial", 12, false, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
thStyle.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
thStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cell.setCellStyle(thStyle);
}
//数据的样式
if (rowId != 1) {
if (strings.get(i) instanceof Double
|| strings.get(i) instanceof Float
|| strings.get(i) instanceof Long
|| strings.get(i) instanceof Integer) {
cell.setCellStyle(numStyle);
} else {
cell.setCellStyle(style);
}
}
//数据类型处理
if (strings.get(i) instanceof Double) {
cell.setCellValue((double) strings.get(i));
} else if (strings.get(i) instanceof Float) {
cell.setCellValue((double) (Float) strings.get(i));
} else if (strings.get(i) instanceof Long) {
cell.setCellValue((double) (Long) strings.get(i));
} else if (strings.get(i) instanceof Integer) {
cell.setCellValue((double) (Integer) strings.get(i));
} else if (strings.get(i) instanceof Date) {
DataFormat format = wb.createDataFormat();
style.setDataFormat(format.getFormat("yyyy-MM-dd"));
cell.setCellValue((Date) strings.get(i));
} else if (strings.get(i) instanceof String) {
cell.setCellValue((String) strings.get(i));
} else {
try {
cell.setCellValue((String) Class.forName(this.getClass()
.getName()
.replaceAll(this.getClass()
.getSimpleName(), "fieldtype." + strings.get(i)
.getClass()
.getSimpleName() + "Type"))
.getMethod("setValue", Object.class)
.invoke((Object) null, strings.get(i)));
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException |
ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
rowId++;
}
//输出Excel
return outputFile(fileName);
}
/**
* 设置单元格字体样式
*
* @param fontType 字体类型
* @param fontSize 字体大小
* @param bold 字体是否加粗
* @param textAlign_l_a_r 字体对齐方式(左右)
* @param textAlign_t_a_b 字体对齐方式(上下)
* @return CellStyle
*/
public CellStyle setCellStyle(String fontType, int fontSize, boolean bold, HorizontalAlignment textAlign_l_a_r, VerticalAlignment textAlign_t_a_b) {
HSSFCellStyle cellStyle = wb.createCellStyle();
if (textAlign_l_a_r != null) {
cellStyle.setAlignment(textAlign_l_a_r);//设置对齐方式
}
if (textAlign_t_a_b != null) {
cellStyle.setVerticalAlignment(textAlign_t_a_b); //设置对齐方式
}
HSSFFont font = wb.createFont();
font.setFontName(fontType);
font.setFontHeightInPoints((short) fontSize);
font.setBold(bold);
cellStyle.setFont(font);// 设置字体
return cellStyle;
}
/**
* 文件输出流
*
* @param fileName 文件名
* @return 返回是否成功
*/
private Boolean outputFile(String fileName) {
FileOutputStream output = null;
try {
output = new FileOutputStream("D://" + fileName + ".xls");
wb.write(output);
output.flush();
output.close();
return true;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
后面还会对这个类进行持续的修改优化!!!!,希望可以给各位有一定的帮助!!欢迎讨论分享