公司给我下发一个关于EXCEL导出的功能,引出了以下的内容。以下内容只进行相互交流学习,欢迎批评指正。
其实,关于EXCEL导出的功能网上有很多的教程,也可以很快的实现这个功能。如果系统存在多个EXCEL导出呢?是不是会存在大量的重复代码呢?如何将重复的代码与不重复的代码相互隔离,又能很好的调用呢?
基于上面的问题,如何正确的设计呢?JAVA反射可以获取一个类的字段的值,泛型可以基于一个父类进行扩展,那么可以基于此来 获取相关的sheet头的信息,以及EXCEL的实体信息。实现代码如下:
/**
* excel导出功能
* 以反射的方式,实现导出excel。以便后续的复用等
* 注意:头信息字段与实体信息字段的顺序必须一致,否则会出现数据错乱的问题
*/
public class ExcelUtil {
/**
* 每一行数据赋值
* @param info 实体信息值
* @param sheet 实体页
* @param row 行数
*/
private void createExcleRow(Object info ,final HSSFSheet sheet,int row){
try {
// 获取真实的类名
String className = info.getClass().getName();
Class clazz = Class.forName(className);
// 类字段信息
Field[] fields = clazz.getDeclaredFields();
// 创建excel行
HSSFRow headerRow = sheet.createRow(row);
for(int i = 0; i < fields.length ; i ++ ){
Field field = fields[i];
field.setAccessible(true);
String alvue = (String)field.get(info);
HSSFCell cell = headerRow.createCell(i);
cell.setCellValue(alvue);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* 设置excel实体信息
* @param excelInfo
* @param sheet
*/
private void createExcelInfo(List<? extends Object> excelInfo,final HSSFSheet sheet){
int size = excelInfo.size() ;
for(int i = 0 ; i < size ; i ++){
createExcleRow(excelInfo.get(i),sheet,(i+1));
}
}
/**
* 单一实体页EXCEl生成方法
* @param headerInfo EXCEL表头信息
* @param excelInfo EXCEL实体信息
* @return 返回excel数据
*/
public HSSFWorkbook createSingleSheetExcel(Object headerInfo, List<? extends Object> excelInfo){
final HSSFWorkbook workbook = new HSSFWorkbook();
// 创建sheer头行
HSSFSheet sheet = workbook.createSheet();
// 设置头信息
createExcleRow(headerInfo,sheet,0);
// 设置实体数据
createExcelInfo(excelInfo,sheet);
return workbook;
}
}
其实细想一下,上述代码存在问题。一个EXCEL有可能不只是一个实体页或者需要设置单元格的格式怎么办呢?
根据设计模式的开闭原则,可以将变动的对外开放,对不变的对外关闭,代码如下:
public abstract class AbstractExcelBuilder {
/**
* 每一行数据赋值
* @param info 实体信息值
* @param sheet 实体页
* @param row 行数
*/
public final void createExcleRow(Object info , final HSSFSheet sheet, int row){
try {
// 获取真实的类名
String className = info.getClass().getName();
Class clazz = Class.forName(className);
// 类字段信息
Field[] fields = clazz.getDeclaredFields();
// 创建excel行
HSSFRow headerRow = sheet.createRow(row);
for(int i = 0; i < fields.length ; i ++ ){
Field field = fields[i];
field.setAccessible(true);
String alvue = (String)field.get(info);
HSSFCell cell = headerRow.createCell(i);
cell.setCellValue(alvue);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* 设置excel实体信息
* @param excelInfo
* @param sheet
*/
public abstract void createExcelInfo(final HSSFSheet sheet,List<? extends Object> excelInfo );
/**
* 设置excel格式
* @param excelInfo
* @param sheet
*/
public abstract void createExcelStyle(final HSSFSheet sheet,List<? extends Object> excelInfo );
/**
* 生成EXCEL方法
* @param headerInfos excel头信息;如果存在多个EXCEL Sheet,该list的顺序,与实际EXCEL的生成顺序一致
* @param excelInfos EXCEL实体信息
* @return 返回EXCEL信息
*/
public HSSFWorkbook createExcel(List<Object> headerInfos, List<? extends Object> ... excelInfos){
if(headerInfos.size() != excelInfos.length){
throw new IllegalArgumentException("参数不正确");
}
final HSSFWorkbook workbook = new HSSFWorkbook();
for(int i = 0 ; i < headerInfos.size() ; i++){
// 创建sheer头行
HSSFSheet sheet = workbook.createSheet();
// 设置头信息
createExcleRow(headerInfos.get(i),sheet,0);
// 设置实体数据
createExcelInfo(sheet,excelInfos[i]);
// 设置Excel格式
createExcelInfo(sheet,excelInfos[i]);
}
return workbook;
}
}
实现类如下:
**
* excel单实体页创建类
*/
@Component
public class SingleSheetExcleBuilder extends AbstractExcelBuilder{
/**
* 设置excel实体信息,单实体页不允许多个excelInfo实体信息。
* 如果存在多个实体信息,则抛出异常。
* @param excelInfo 实体页的信息
* @param sheet 实体页
*/
@Override
public void createExcelInfo(HSSFSheet sheet, List<?> excelInfo) {
for(int i = 0 ; i < excelInfo.size() ; i ++){
createExcleRow(excelInfo.get(i),sheet,(i+1));
}
}
/**
* 暂不需要设置EXCEL格式,故不进行设置
* @param sheet 实体页
* @param excelInfo excel实体信息
*/
@Override
public void createExcelStyle(HSSFSheet sheet, List<?> excelInfo) {
}
@Override
public HSSFWorkbook createExcel(List<Object> headerInfos, List<?>... excelInfo) {
return super.createExcel(headerInfos, excelInfo);
}
}
留一个问题,这样做数据会不会错乱呢?